]> git.proxmox.com Git - mirror_qemu.git/blame - target/arm/translate-a64.c
target/arm/translate-a64: Don't underdecode SIMD ld/st single
[mirror_qemu.git] / target / arm / translate-a64.c
CommitLineData
14ade10f
AG
1/*
2 * AArch64 translation
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
74c21bd0 19#include "qemu/osdep.h"
14ade10f
AG
20
21#include "cpu.h"
63c91552 22#include "exec/exec-all.h"
14ade10f 23#include "tcg-op.h"
bc48092f 24#include "tcg-op-gvec.h"
14ade10f 25#include "qemu/log.h"
1d854765 26#include "arm_ldst.h"
14ade10f 27#include "translate.h"
ccd38087 28#include "internals.h"
14ade10f
AG
29#include "qemu/host-utils.h"
30
8012c84f 31#include "exec/semihost.h"
40f860cd
PM
32#include "exec/gen-icount.h"
33
2ef6175a
RH
34#include "exec/helper-proto.h"
35#include "exec/helper-gen.h"
508127e2 36#include "exec/log.h"
14ade10f 37
a7e30d84 38#include "trace-tcg.h"
8c71baed 39#include "translate-a64.h"
62823083 40#include "qemu/atomic128.h"
a7e30d84 41
14ade10f
AG
42static TCGv_i64 cpu_X[32];
43static TCGv_i64 cpu_pc;
14ade10f 44
fa2ef212 45/* Load/store exclusive handling */
fa2ef212 46static TCGv_i64 cpu_exclusive_high;
fa2ef212 47
14ade10f
AG
48static const char *regnames[] = {
49 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
50 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
51 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
52 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
53};
54
832ffa1c
AG
55enum a64_shift_type {
56 A64_SHIFT_TYPE_LSL = 0,
57 A64_SHIFT_TYPE_LSR = 1,
58 A64_SHIFT_TYPE_ASR = 2,
59 A64_SHIFT_TYPE_ROR = 3
60};
61
384b26fb
AB
62/* Table based decoder typedefs - used when the relevant bits for decode
63 * are too awkwardly scattered across the instruction (eg SIMD).
64 */
65typedef void AArch64DecodeFn(DisasContext *s, uint32_t insn);
66
67typedef struct AArch64DecodeTable {
68 uint32_t pattern;
69 uint32_t mask;
70 AArch64DecodeFn *disas_fn;
71} AArch64DecodeTable;
72
1f8a73af 73/* Function prototype for gen_ functions for calling Neon helpers */
0a79bc87 74typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
1f8a73af 75typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
6d9571f7 76typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
70d7f984 77typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
a847f32c 78typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
d980fd59
PM
79typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
80typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
70d7f984 81typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
8908f4d1
AB
82typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
83typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
6781fa11 84typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
1a66ac61
RH
85typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
86typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
87typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
74608ea4 88typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, TCGMemOp);
1f8a73af 89
14ade10f
AG
90/* initialize TCG globals. */
91void a64_translate_init(void)
92{
93 int i;
94
e1ccc054 95 cpu_pc = tcg_global_mem_new_i64(cpu_env,
14ade10f
AG
96 offsetof(CPUARMState, pc),
97 "pc");
98 for (i = 0; i < 32; i++) {
e1ccc054 99 cpu_X[i] = tcg_global_mem_new_i64(cpu_env,
14ade10f
AG
100 offsetof(CPUARMState, xregs[i]),
101 regnames[i]);
102 }
103
e1ccc054 104 cpu_exclusive_high = tcg_global_mem_new_i64(cpu_env,
fa2ef212 105 offsetof(CPUARMState, exclusive_high), "exclusive_high");
14ade10f
AG
106}
107
8bd5c820 108static inline int get_a64_user_mem_index(DisasContext *s)
579d21cc 109{
8bd5c820 110 /* Return the core mmu_idx to use for A64 "unprivileged load/store" insns:
579d21cc
PM
111 * if EL1, access as if EL0; otherwise access at current EL
112 */
8bd5c820
PM
113 ARMMMUIdx useridx;
114
579d21cc
PM
115 switch (s->mmu_idx) {
116 case ARMMMUIdx_S12NSE1:
8bd5c820
PM
117 useridx = ARMMMUIdx_S12NSE0;
118 break;
579d21cc 119 case ARMMMUIdx_S1SE1:
8bd5c820
PM
120 useridx = ARMMMUIdx_S1SE0;
121 break;
579d21cc
PM
122 case ARMMMUIdx_S2NS:
123 g_assert_not_reached();
124 default:
8bd5c820
PM
125 useridx = s->mmu_idx;
126 break;
579d21cc 127 }
8bd5c820 128 return arm_to_core_mmu_idx(useridx);
579d21cc
PM
129}
130
14ade10f
AG
131void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
132 fprintf_function cpu_fprintf, int flags)
133{
134 ARMCPU *cpu = ARM_CPU(cs);
135 CPUARMState *env = &cpu->env;
d356312f 136 uint32_t psr = pstate_read(env);
14ade10f 137 int i;
08b8e0f5 138 int el = arm_current_el(env);
06e5cf7a 139 const char *ns_status;
14ade10f 140
3cb506a3
RH
141 cpu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
142 for (i = 0; i < 32; i++) {
143 if (i == 31) {
144 cpu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
14ade10f 145 } else {
3cb506a3
RH
146 cpu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
147 (i + 2) % 3 ? " " : "\n");
14ade10f
AG
148 }
149 }
06e5cf7a
PM
150
151 if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
152 ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
153 } else {
154 ns_status = "";
155 }
2bf5f3f9 156 cpu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
d356312f
PM
157 psr,
158 psr & PSTATE_N ? 'N' : '-',
159 psr & PSTATE_Z ? 'Z' : '-',
160 psr & PSTATE_C ? 'C' : '-',
08b8e0f5 161 psr & PSTATE_V ? 'V' : '-',
06e5cf7a 162 ns_status,
08b8e0f5
PM
163 el,
164 psr & PSTATE_SP ? 'h' : 't');
f6d8a314 165
2bf5f3f9
RH
166 if (!(flags & CPU_DUMP_FPU)) {
167 cpu_fprintf(f, "\n");
168 return;
169 }
ced31551
RH
170 if (fp_exception_el(env, el) != 0) {
171 cpu_fprintf(f, " FPU disabled\n");
172 return;
173 }
2bf5f3f9
RH
174 cpu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
175 vfp_get_fpcr(env), vfp_get_fpsr(env));
176
cd208a1c 177 if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
ced31551 178 int j, zcr_len = sve_zcr_len_for_el(env, el);
2bf5f3f9
RH
179
180 for (i = 0; i <= FFR_PRED_NUM; i++) {
181 bool eol;
182 if (i == FFR_PRED_NUM) {
183 cpu_fprintf(f, "FFR=");
184 /* It's last, so end the line. */
185 eol = true;
186 } else {
187 cpu_fprintf(f, "P%02d=", i);
188 switch (zcr_len) {
189 case 0:
190 eol = i % 8 == 7;
191 break;
192 case 1:
193 eol = i % 6 == 5;
194 break;
195 case 2:
196 case 3:
197 eol = i % 3 == 2;
198 break;
199 default:
200 /* More than one quadword per predicate. */
201 eol = true;
202 break;
203 }
204 }
205 for (j = zcr_len / 4; j >= 0; j--) {
206 int digits;
207 if (j * 4 + 4 <= zcr_len + 1) {
208 digits = 16;
209 } else {
210 digits = (zcr_len % 4 + 1) * 4;
211 }
212 cpu_fprintf(f, "%0*" PRIx64 "%s", digits,
213 env->vfp.pregs[i].p[j],
214 j ? ":" : eol ? "\n" : " ");
215 }
216 }
217
218 for (i = 0; i < 32; i++) {
219 if (zcr_len == 0) {
220 cpu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
221 i, env->vfp.zregs[i].d[1],
222 env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
223 } else if (zcr_len == 1) {
224 cpu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
225 ":%016" PRIx64 ":%016" PRIx64 "\n",
226 i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
227 env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
228 } else {
229 for (j = zcr_len; j >= 0; j--) {
230 bool odd = (zcr_len - j) % 2 != 0;
231 if (j == zcr_len) {
232 cpu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
233 } else if (!odd) {
234 if (j > 0) {
235 cpu_fprintf(f, " [%x-%x]=", j, j - 1);
236 } else {
237 cpu_fprintf(f, " [%x]=", j);
238 }
239 }
240 cpu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
241 env->vfp.zregs[i].d[j * 2 + 1],
242 env->vfp.zregs[i].d[j * 2],
243 odd || j == 0 ? "\n" : ":");
244 }
245 }
246 }
247 } else {
248 for (i = 0; i < 32; i++) {
9a2b5256 249 uint64_t *q = aa64_vfp_qreg(env, i);
2bf5f3f9
RH
250 cpu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
251 i, q[1], q[0], (i & 1 ? "\n" : " "));
f6d8a314 252 }
f6d8a314 253 }
14ade10f
AG
254}
255
256void gen_a64_set_pc_im(uint64_t val)
257{
258 tcg_gen_movi_i64(cpu_pc, val);
259}
260
6feecb8b
TH
261/* Load the PC from a generic TCG variable.
262 *
263 * If address tagging is enabled via the TCR TBI bits, then loading
8733d762 264 * an address into the PC will clear out any tag in it:
6feecb8b
TH
265 * + for EL2 and EL3 there is only one TBI bit, and if it is set
266 * then the address is zero-extended, clearing bits [63:56]
267 * + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
268 * and TBI1 controls addressses with bit 55 == 1.
269 * If the appropriate TBI bit is set for the address then
270 * the address is sign-extended from bit 55 into bits [63:56]
271 *
272 * We can avoid doing this for relative-branches, because the
273 * PC + offset can never overflow into the tag bits (assuming
274 * that virtual addresses are less than 56 bits wide, as they
275 * are currently), but we must handle it for branch-to-register.
276 */
277static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
278{
476a4692
RH
279 /* Note that TBII is TBI1:TBI0. */
280 int tbi = s->tbii;
6feecb8b
TH
281
282 if (s->current_el <= 1) {
8733d762
RH
283 if (tbi != 0) {
284 /* Sign-extend from bit 55. */
285 tcg_gen_sextract_i64(cpu_pc, src, 0, 56);
6feecb8b 286
8733d762
RH
287 if (tbi != 3) {
288 TCGv_i64 tcg_zero = tcg_const_i64(0);
6feecb8b 289
8733d762
RH
290 /*
291 * The two TBI bits differ.
292 * If tbi0, then !tbi1: only use the extension if positive.
293 * if !tbi0, then tbi1: only use the extension if negative.
294 */
295 tcg_gen_movcond_i64(tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
296 cpu_pc, cpu_pc, tcg_zero, cpu_pc, src);
297 tcg_temp_free_i64(tcg_zero);
6feecb8b 298 }
8733d762 299 return;
6feecb8b 300 }
8733d762 301 } else {
476a4692 302 if (tbi != 0) {
6feecb8b 303 /* Force tag byte to all zero */
8733d762
RH
304 tcg_gen_extract_i64(cpu_pc, src, 0, 56);
305 return;
6feecb8b
TH
306 }
307 }
8733d762
RH
308
309 /* Load unmodified address */
310 tcg_gen_mov_i64(cpu_pc, src);
6feecb8b
TH
311}
312
259cb684
RH
313typedef struct DisasCompare64 {
314 TCGCond cond;
315 TCGv_i64 value;
316} DisasCompare64;
317
318static void a64_test_cc(DisasCompare64 *c64, int cc)
319{
320 DisasCompare c32;
321
322 arm_test_cc(&c32, cc);
323
324 /* Sign-extend the 32-bit value so that the GE/LT comparisons work
325 * properly. The NE/EQ comparisons are also fine with this choice. */
326 c64->cond = c32.cond;
327 c64->value = tcg_temp_new_i64();
328 tcg_gen_ext_i32_i64(c64->value, c32.value);
329
330 arm_free_cc(&c32);
331}
332
333static void a64_free_cc(DisasCompare64 *c64)
334{
335 tcg_temp_free_i64(c64->value);
336}
337
d4a2dc67 338static void gen_exception_internal(int excp)
14ade10f 339{
d4a2dc67
PM
340 TCGv_i32 tcg_excp = tcg_const_i32(excp);
341
342 assert(excp_is_internal(excp));
343 gen_helper_exception_internal(cpu_env, tcg_excp);
344 tcg_temp_free_i32(tcg_excp);
345}
346
73710361 347static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
d4a2dc67
PM
348{
349 TCGv_i32 tcg_excp = tcg_const_i32(excp);
350 TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
73710361 351 TCGv_i32 tcg_el = tcg_const_i32(target_el);
d4a2dc67 352
73710361
GB
353 gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
354 tcg_syn, tcg_el);
355 tcg_temp_free_i32(tcg_el);
d4a2dc67
PM
356 tcg_temp_free_i32(tcg_syn);
357 tcg_temp_free_i32(tcg_excp);
358}
359
360static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
361{
362 gen_a64_set_pc_im(s->pc - offset);
363 gen_exception_internal(excp);
dcba3a8d 364 s->base.is_jmp = DISAS_NORETURN;
14ade10f
AG
365}
366
d4a2dc67 367static void gen_exception_insn(DisasContext *s, int offset, int excp,
73710361 368 uint32_t syndrome, uint32_t target_el)
14ade10f
AG
369{
370 gen_a64_set_pc_im(s->pc - offset);
73710361 371 gen_exception(excp, syndrome, target_el);
dcba3a8d 372 s->base.is_jmp = DISAS_NORETURN;
40f860cd
PM
373}
374
c900a2e6
PM
375static void gen_exception_bkpt_insn(DisasContext *s, int offset,
376 uint32_t syndrome)
377{
378 TCGv_i32 tcg_syn;
379
380 gen_a64_set_pc_im(s->pc - offset);
381 tcg_syn = tcg_const_i32(syndrome);
382 gen_helper_exception_bkpt_insn(cpu_env, tcg_syn);
383 tcg_temp_free_i32(tcg_syn);
384 s->base.is_jmp = DISAS_NORETURN;
385}
386
7ea47fe7
PM
387static void gen_ss_advance(DisasContext *s)
388{
389 /* If the singlestep state is Active-not-pending, advance to
390 * Active-pending.
391 */
392 if (s->ss_active) {
393 s->pstate_ss = 0;
394 gen_helper_clear_pstate_ss(cpu_env);
395 }
396}
397
398static void gen_step_complete_exception(DisasContext *s)
399{
400 /* We just completed step of an insn. Move from Active-not-pending
401 * to Active-pending, and then also take the swstep exception.
402 * This corresponds to making the (IMPDEF) choice to prioritize
403 * swstep exceptions over asynchronous exceptions taken to an exception
404 * level where debug is disabled. This choice has the advantage that
405 * we do not need to maintain internal state corresponding to the
406 * ISV/EX syndrome bits between completion of the step and generation
407 * of the exception, and our syndrome information is always correct.
408 */
409 gen_ss_advance(s);
73710361
GB
410 gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
411 default_exception_el(s));
dcba3a8d 412 s->base.is_jmp = DISAS_NORETURN;
7ea47fe7
PM
413}
414
40f860cd
PM
415static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
416{
7ea47fe7
PM
417 /* No direct tb linking with singlestep (either QEMU's or the ARM
418 * debug architecture kind) or deterministic io
419 */
c5a49c63
EC
420 if (s->base.singlestep_enabled || s->ss_active ||
421 (tb_cflags(s->base.tb) & CF_LAST_IO)) {
40f860cd
PM
422 return false;
423 }
424
90aa39a1 425#ifndef CONFIG_USER_ONLY
40f860cd 426 /* Only link tbs from inside the same guest page */
dcba3a8d 427 if ((s->base.tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
40f860cd
PM
428 return false;
429 }
90aa39a1 430#endif
40f860cd
PM
431
432 return true;
433}
434
435static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
436{
437 TranslationBlock *tb;
438
dcba3a8d 439 tb = s->base.tb;
40f860cd
PM
440 if (use_goto_tb(s, n, dest)) {
441 tcg_gen_goto_tb(n);
442 gen_a64_set_pc_im(dest);
07ea28b4 443 tcg_gen_exit_tb(tb, n);
dcba3a8d 444 s->base.is_jmp = DISAS_NORETURN;
40f860cd
PM
445 } else {
446 gen_a64_set_pc_im(dest);
7ea47fe7
PM
447 if (s->ss_active) {
448 gen_step_complete_exception(s);
dcba3a8d 449 } else if (s->base.singlestep_enabled) {
d4a2dc67 450 gen_exception_internal(EXCP_DEBUG);
cc9c1ed1 451 } else {
7f11636d 452 tcg_gen_lookup_and_goto_ptr();
dcba3a8d 453 s->base.is_jmp = DISAS_NORETURN;
40f860cd 454 }
40f860cd 455 }
14ade10f
AG
456}
457
8c71baed 458void unallocated_encoding(DisasContext *s)
14ade10f 459{
d4a2dc67 460 /* Unallocated and reserved encodings are uncategorized */
73710361
GB
461 gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
462 default_exception_el(s));
14ade10f
AG
463}
464
11e169de
AG
465static void init_tmp_a64_array(DisasContext *s)
466{
467#ifdef CONFIG_DEBUG_TCG
f764718d 468 memset(s->tmp_a64, 0, sizeof(s->tmp_a64));
11e169de
AG
469#endif
470 s->tmp_a64_count = 0;
471}
472
473static void free_tmp_a64(DisasContext *s)
474{
475 int i;
476 for (i = 0; i < s->tmp_a64_count; i++) {
477 tcg_temp_free_i64(s->tmp_a64[i]);
478 }
479 init_tmp_a64_array(s);
480}
481
8c71baed 482TCGv_i64 new_tmp_a64(DisasContext *s)
11e169de
AG
483{
484 assert(s->tmp_a64_count < TMP_A64_MAX);
485 return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
486}
487
8c71baed 488TCGv_i64 new_tmp_a64_zero(DisasContext *s)
11e169de
AG
489{
490 TCGv_i64 t = new_tmp_a64(s);
491 tcg_gen_movi_i64(t, 0);
492 return t;
493}
494
71b46089
AG
495/*
496 * Register access functions
497 *
498 * These functions are used for directly accessing a register in where
499 * changes to the final register value are likely to be made. If you
500 * need to use a register for temporary calculation (e.g. index type
501 * operations) use the read_* form.
502 *
503 * B1.2.1 Register mappings
504 *
505 * In instruction register encoding 31 can refer to ZR (zero register) or
506 * the SP (stack pointer) depending on context. In QEMU's case we map SP
507 * to cpu_X[31] and ZR accesses to a temporary which can be discarded.
508 * This is the point of the _sp forms.
509 */
8c71baed 510TCGv_i64 cpu_reg(DisasContext *s, int reg)
11e169de
AG
511{
512 if (reg == 31) {
513 return new_tmp_a64_zero(s);
514 } else {
515 return cpu_X[reg];
516 }
517}
518
71b46089 519/* register access for when 31 == SP */
8c71baed 520TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
71b46089
AG
521{
522 return cpu_X[reg];
523}
524
60e53388
AG
525/* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
526 * representing the register contents. This TCGv is an auto-freed
527 * temporary so it need not be explicitly freed, and may be modified.
528 */
8c71baed 529TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
60e53388
AG
530{
531 TCGv_i64 v = new_tmp_a64(s);
532 if (reg != 31) {
533 if (sf) {
534 tcg_gen_mov_i64(v, cpu_X[reg]);
535 } else {
536 tcg_gen_ext32u_i64(v, cpu_X[reg]);
537 }
538 } else {
539 tcg_gen_movi_i64(v, 0);
540 }
541 return v;
542}
543
8c71baed 544TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
4a08d475
PM
545{
546 TCGv_i64 v = new_tmp_a64(s);
547 if (sf) {
548 tcg_gen_mov_i64(v, cpu_X[reg]);
549 } else {
550 tcg_gen_ext32u_i64(v, cpu_X[reg]);
551 }
552 return v;
553}
554
e2f90565
PM
555/* Return the offset into CPUARMState of a slice (from
556 * the least significant end) of FP register Qn (ie
557 * Dn, Sn, Hn or Bn).
558 * (Note that this is not the same mapping as for A32; see cpu.h)
559 */
90e49638 560static inline int fp_reg_offset(DisasContext *s, int regno, TCGMemOp size)
e2f90565 561{
9a2b5256 562 return vec_reg_offset(s, regno, 0, size);
e2f90565
PM
563}
564
565/* Offset of the high half of the 128 bit vector Qn */
90e49638 566static inline int fp_reg_hi_offset(DisasContext *s, int regno)
e2f90565 567{
9a2b5256 568 return vec_reg_offset(s, regno, 1, MO_64);
e2f90565
PM
569}
570
ec73d2e0
AG
571/* Convenience accessors for reading and writing single and double
572 * FP registers. Writing clears the upper parts of the associated
573 * 128 bit vector register, as required by the architecture.
574 * Note that unlike the GP register accessors, the values returned
575 * by the read functions must be manually freed.
576 */
577static TCGv_i64 read_fp_dreg(DisasContext *s, int reg)
578{
579 TCGv_i64 v = tcg_temp_new_i64();
580
90e49638 581 tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(s, reg, MO_64));
ec73d2e0
AG
582 return v;
583}
584
585static TCGv_i32 read_fp_sreg(DisasContext *s, int reg)
586{
587 TCGv_i32 v = tcg_temp_new_i32();
588
90e49638 589 tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(s, reg, MO_32));
ec73d2e0
AG
590 return v;
591}
592
3d99d931
RH
593static TCGv_i32 read_fp_hreg(DisasContext *s, int reg)
594{
595 TCGv_i32 v = tcg_temp_new_i32();
596
597 tcg_gen_ld16u_i32(v, cpu_env, fp_reg_offset(s, reg, MO_16));
598 return v;
599}
600
4ff55bcb
RH
601/* Clear the bits above an N-bit vector, for N = (is_q ? 128 : 64).
602 * If SVE is not enabled, then there are only 128 bits in the vector.
603 */
604static void clear_vec_high(DisasContext *s, bool is_q, int rd)
605{
606 unsigned ofs = fp_reg_offset(s, rd, MO_64);
607 unsigned vsz = vec_full_reg_size(s);
608
609 if (!is_q) {
610 TCGv_i64 tcg_zero = tcg_const_i64(0);
611 tcg_gen_st_i64(tcg_zero, cpu_env, ofs + 8);
612 tcg_temp_free_i64(tcg_zero);
613 }
614 if (vsz > 16) {
615 tcg_gen_gvec_dup8i(ofs + 16, vsz - 16, vsz - 16, 0);
616 }
617}
618
8c71baed 619void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
ec73d2e0 620{
4ff55bcb 621 unsigned ofs = fp_reg_offset(s, reg, MO_64);
ec73d2e0 622
4ff55bcb
RH
623 tcg_gen_st_i64(v, cpu_env, ofs);
624 clear_vec_high(s, false, reg);
ec73d2e0
AG
625}
626
627static void write_fp_sreg(DisasContext *s, int reg, TCGv_i32 v)
628{
629 TCGv_i64 tmp = tcg_temp_new_i64();
630
631 tcg_gen_extu_i32_i64(tmp, v);
632 write_fp_dreg(s, reg, tmp);
633 tcg_temp_free_i64(tmp);
634}
635
8c71baed 636TCGv_ptr get_fpstatus_ptr(bool is_f16)
ec73d2e0
AG
637{
638 TCGv_ptr statusptr = tcg_temp_new_ptr();
639 int offset;
640
d81ce0ef
AB
641 /* In A64 all instructions (both FP and Neon) use the FPCR; there
642 * is no equivalent of the A32 Neon "standard FPSCR value".
643 * However half-precision operations operate under a different
644 * FZ16 flag and use vfp.fp_status_f16 instead of vfp.fp_status.
ec73d2e0 645 */
d81ce0ef
AB
646 if (is_f16) {
647 offset = offsetof(CPUARMState, vfp.fp_status_f16);
648 } else {
649 offset = offsetof(CPUARMState, vfp.fp_status);
650 }
ec73d2e0
AG
651 tcg_gen_addi_ptr(statusptr, cpu_env, offset);
652 return statusptr;
653}
654
377ef731
RH
655/* Expand a 2-operand AdvSIMD vector operation using an expander function. */
656static void gen_gvec_fn2(DisasContext *s, bool is_q, int rd, int rn,
657 GVecGen2Fn *gvec_fn, int vece)
658{
659 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
660 is_q ? 16 : 8, vec_full_reg_size(s));
661}
662
cdb45a60
RH
663/* Expand a 2-operand + immediate AdvSIMD vector operation using
664 * an expander function.
665 */
666static void gen_gvec_fn2i(DisasContext *s, bool is_q, int rd, int rn,
667 int64_t imm, GVecGen2iFn *gvec_fn, int vece)
668{
669 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
670 imm, is_q ? 16 : 8, vec_full_reg_size(s));
671}
672
bc48092f
RH
673/* Expand a 3-operand AdvSIMD vector operation using an expander function. */
674static void gen_gvec_fn3(DisasContext *s, bool is_q, int rd, int rn, int rm,
675 GVecGen3Fn *gvec_fn, int vece)
676{
677 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
678 vec_full_reg_offset(s, rm), is_q ? 16 : 8, vec_full_reg_size(s));
679}
680
cdb45a60
RH
681/* Expand a 2-operand + immediate AdvSIMD vector operation using
682 * an op descriptor.
683 */
684static void gen_gvec_op2i(DisasContext *s, bool is_q, int rd,
685 int rn, int64_t imm, const GVecGen2i *gvec_op)
686{
687 tcg_gen_gvec_2i(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
688 is_q ? 16 : 8, vec_full_reg_size(s), imm, gvec_op);
689}
690
bc48092f
RH
691/* Expand a 3-operand AdvSIMD vector operation using an op descriptor. */
692static void gen_gvec_op3(DisasContext *s, bool is_q, int rd,
693 int rn, int rm, const GVecGen3 *gvec_op)
694{
695 tcg_gen_gvec_3(vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
696 vec_full_reg_offset(s, rm), is_q ? 16 : 8,
697 vec_full_reg_size(s), gvec_op);
698}
699
26c470a7
RH
700/* Expand a 3-operand operation using an out-of-line helper. */
701static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd,
702 int rn, int rm, int data, gen_helper_gvec_3 *fn)
703{
704 tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd),
705 vec_full_reg_offset(s, rn),
706 vec_full_reg_offset(s, rm),
707 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
708}
709
e7186d82
RH
710/* Expand a 3-operand + env pointer operation using
711 * an out-of-line helper.
712 */
713static void gen_gvec_op3_env(DisasContext *s, bool is_q, int rd,
714 int rn, int rm, gen_helper_gvec_3_ptr *fn)
715{
716 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
717 vec_full_reg_offset(s, rn),
718 vec_full_reg_offset(s, rm), cpu_env,
719 is_q ? 16 : 8, vec_full_reg_size(s), 0, fn);
720}
721
1695cd61
RH
722/* Expand a 3-operand + fpstatus pointer + simd data value operation using
723 * an out-of-line helper.
724 */
725static void gen_gvec_op3_fpst(DisasContext *s, bool is_q, int rd, int rn,
726 int rm, bool is_fp16, int data,
727 gen_helper_gvec_3_ptr *fn)
728{
729 TCGv_ptr fpst = get_fpstatus_ptr(is_fp16);
730 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
731 vec_full_reg_offset(s, rn),
732 vec_full_reg_offset(s, rm), fpst,
733 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
734 tcg_temp_free_ptr(fpst);
735}
736
832ffa1c
AG
737/* Set ZF and NF based on a 64 bit result. This is alas fiddlier
738 * than the 32 bit equivalent.
739 */
740static inline void gen_set_NZ64(TCGv_i64 result)
741{
7cb36e18
RH
742 tcg_gen_extr_i64_i32(cpu_ZF, cpu_NF, result);
743 tcg_gen_or_i32(cpu_ZF, cpu_ZF, cpu_NF);
832ffa1c
AG
744}
745
746/* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
747static inline void gen_logic_CC(int sf, TCGv_i64 result)
748{
749 if (sf) {
750 gen_set_NZ64(result);
751 } else {
ecc7b3aa 752 tcg_gen_extrl_i64_i32(cpu_ZF, result);
7cb36e18 753 tcg_gen_mov_i32(cpu_NF, cpu_ZF);
832ffa1c
AG
754 }
755 tcg_gen_movi_i32(cpu_CF, 0);
756 tcg_gen_movi_i32(cpu_VF, 0);
757}
758
b0ff21b4
AB
759/* dest = T0 + T1; compute C, N, V and Z flags */
760static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
761{
762 if (sf) {
763 TCGv_i64 result, flag, tmp;
764 result = tcg_temp_new_i64();
765 flag = tcg_temp_new_i64();
766 tmp = tcg_temp_new_i64();
767
768 tcg_gen_movi_i64(tmp, 0);
769 tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
770
ecc7b3aa 771 tcg_gen_extrl_i64_i32(cpu_CF, flag);
b0ff21b4
AB
772
773 gen_set_NZ64(result);
774
775 tcg_gen_xor_i64(flag, result, t0);
776 tcg_gen_xor_i64(tmp, t0, t1);
777 tcg_gen_andc_i64(flag, flag, tmp);
778 tcg_temp_free_i64(tmp);
7cb36e18 779 tcg_gen_extrh_i64_i32(cpu_VF, flag);
b0ff21b4
AB
780
781 tcg_gen_mov_i64(dest, result);
782 tcg_temp_free_i64(result);
783 tcg_temp_free_i64(flag);
784 } else {
785 /* 32 bit arithmetic */
786 TCGv_i32 t0_32 = tcg_temp_new_i32();
787 TCGv_i32 t1_32 = tcg_temp_new_i32();
788 TCGv_i32 tmp = tcg_temp_new_i32();
789
790 tcg_gen_movi_i32(tmp, 0);
ecc7b3aa
RH
791 tcg_gen_extrl_i64_i32(t0_32, t0);
792 tcg_gen_extrl_i64_i32(t1_32, t1);
b0ff21b4
AB
793 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
794 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
795 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
796 tcg_gen_xor_i32(tmp, t0_32, t1_32);
797 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
798 tcg_gen_extu_i32_i64(dest, cpu_NF);
799
800 tcg_temp_free_i32(tmp);
801 tcg_temp_free_i32(t0_32);
802 tcg_temp_free_i32(t1_32);
803 }
804}
805
806/* dest = T0 - T1; compute C, N, V and Z flags */
807static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
808{
809 if (sf) {
810 /* 64 bit arithmetic */
811 TCGv_i64 result, flag, tmp;
812
813 result = tcg_temp_new_i64();
814 flag = tcg_temp_new_i64();
815 tcg_gen_sub_i64(result, t0, t1);
816
817 gen_set_NZ64(result);
818
819 tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
ecc7b3aa 820 tcg_gen_extrl_i64_i32(cpu_CF, flag);
b0ff21b4
AB
821
822 tcg_gen_xor_i64(flag, result, t0);
823 tmp = tcg_temp_new_i64();
824 tcg_gen_xor_i64(tmp, t0, t1);
825 tcg_gen_and_i64(flag, flag, tmp);
826 tcg_temp_free_i64(tmp);
7cb36e18 827 tcg_gen_extrh_i64_i32(cpu_VF, flag);
b0ff21b4
AB
828 tcg_gen_mov_i64(dest, result);
829 tcg_temp_free_i64(flag);
830 tcg_temp_free_i64(result);
831 } else {
832 /* 32 bit arithmetic */
833 TCGv_i32 t0_32 = tcg_temp_new_i32();
834 TCGv_i32 t1_32 = tcg_temp_new_i32();
835 TCGv_i32 tmp;
836
ecc7b3aa
RH
837 tcg_gen_extrl_i64_i32(t0_32, t0);
838 tcg_gen_extrl_i64_i32(t1_32, t1);
b0ff21b4
AB
839 tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
840 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
841 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
842 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
843 tmp = tcg_temp_new_i32();
844 tcg_gen_xor_i32(tmp, t0_32, t1_32);
845 tcg_temp_free_i32(t0_32);
846 tcg_temp_free_i32(t1_32);
847 tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
848 tcg_temp_free_i32(tmp);
849 tcg_gen_extu_i32_i64(dest, cpu_NF);
850 }
851}
852
643dbb07
CF
853/* dest = T0 + T1 + CF; do not compute flags. */
854static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
855{
856 TCGv_i64 flag = tcg_temp_new_i64();
857 tcg_gen_extu_i32_i64(flag, cpu_CF);
858 tcg_gen_add_i64(dest, t0, t1);
859 tcg_gen_add_i64(dest, dest, flag);
860 tcg_temp_free_i64(flag);
861
862 if (!sf) {
863 tcg_gen_ext32u_i64(dest, dest);
864 }
865}
866
867/* dest = T0 + T1 + CF; compute C, N, V and Z flags. */
868static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
869{
870 if (sf) {
871 TCGv_i64 result, cf_64, vf_64, tmp;
872 result = tcg_temp_new_i64();
873 cf_64 = tcg_temp_new_i64();
874 vf_64 = tcg_temp_new_i64();
875 tmp = tcg_const_i64(0);
876
877 tcg_gen_extu_i32_i64(cf_64, cpu_CF);
878 tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp);
879 tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp);
ecc7b3aa 880 tcg_gen_extrl_i64_i32(cpu_CF, cf_64);
643dbb07
CF
881 gen_set_NZ64(result);
882
883 tcg_gen_xor_i64(vf_64, result, t0);
884 tcg_gen_xor_i64(tmp, t0, t1);
885 tcg_gen_andc_i64(vf_64, vf_64, tmp);
7cb36e18 886 tcg_gen_extrh_i64_i32(cpu_VF, vf_64);
643dbb07
CF
887
888 tcg_gen_mov_i64(dest, result);
889
890 tcg_temp_free_i64(tmp);
891 tcg_temp_free_i64(vf_64);
892 tcg_temp_free_i64(cf_64);
893 tcg_temp_free_i64(result);
894 } else {
895 TCGv_i32 t0_32, t1_32, tmp;
896 t0_32 = tcg_temp_new_i32();
897 t1_32 = tcg_temp_new_i32();
898 tmp = tcg_const_i32(0);
899
ecc7b3aa
RH
900 tcg_gen_extrl_i64_i32(t0_32, t0);
901 tcg_gen_extrl_i64_i32(t1_32, t1);
643dbb07
CF
902 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp);
903 tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp);
904
905 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
906 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
907 tcg_gen_xor_i32(tmp, t0_32, t1_32);
908 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
909 tcg_gen_extu_i32_i64(dest, cpu_NF);
910
911 tcg_temp_free_i32(tmp);
912 tcg_temp_free_i32(t1_32);
913 tcg_temp_free_i32(t0_32);
914 }
915}
916
4a08d475
PM
917/*
918 * Load/Store generators
919 */
920
921/*
60510aed 922 * Store from GPR register to memory.
4a08d475 923 */
60510aed 924static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
aaa1f954
EI
925 TCGv_i64 tcg_addr, int size, int memidx,
926 bool iss_valid,
927 unsigned int iss_srt,
928 bool iss_sf, bool iss_ar)
60510aed
PM
929{
930 g_assert(size <= 3);
aa6489da 931 tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size);
aaa1f954
EI
932
933 if (iss_valid) {
934 uint32_t syn;
935
936 syn = syn_data_abort_with_iss(0,
937 size,
938 false,
939 iss_srt,
940 iss_sf,
941 iss_ar,
942 0, 0, 0, 0, 0, false);
943 disas_set_insn_syndrome(s, syn);
944 }
60510aed
PM
945}
946
4a08d475 947static void do_gpr_st(DisasContext *s, TCGv_i64 source,
aaa1f954
EI
948 TCGv_i64 tcg_addr, int size,
949 bool iss_valid,
950 unsigned int iss_srt,
951 bool iss_sf, bool iss_ar)
4a08d475 952{
aaa1f954
EI
953 do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s),
954 iss_valid, iss_srt, iss_sf, iss_ar);
4a08d475
PM
955}
956
957/*
958 * Load from memory to GPR register
959 */
aaa1f954
EI
960static void do_gpr_ld_memidx(DisasContext *s,
961 TCGv_i64 dest, TCGv_i64 tcg_addr,
962 int size, bool is_signed,
963 bool extend, int memidx,
964 bool iss_valid, unsigned int iss_srt,
965 bool iss_sf, bool iss_ar)
4a08d475 966{
aa6489da 967 TCGMemOp memop = s->be_data + size;
4a08d475
PM
968
969 g_assert(size <= 3);
970
971 if (is_signed) {
972 memop += MO_SIGN;
973 }
974
60510aed 975 tcg_gen_qemu_ld_i64(dest, tcg_addr, memidx, memop);
4a08d475
PM
976
977 if (extend && is_signed) {
978 g_assert(size < 3);
979 tcg_gen_ext32u_i64(dest, dest);
980 }
aaa1f954
EI
981
982 if (iss_valid) {
983 uint32_t syn;
984
985 syn = syn_data_abort_with_iss(0,
986 size,
987 is_signed,
988 iss_srt,
989 iss_sf,
990 iss_ar,
991 0, 0, 0, 0, 0, false);
992 disas_set_insn_syndrome(s, syn);
993 }
4a08d475
PM
994}
995
aaa1f954
EI
996static void do_gpr_ld(DisasContext *s,
997 TCGv_i64 dest, TCGv_i64 tcg_addr,
998 int size, bool is_signed, bool extend,
999 bool iss_valid, unsigned int iss_srt,
1000 bool iss_sf, bool iss_ar)
60510aed
PM
1001{
1002 do_gpr_ld_memidx(s, dest, tcg_addr, size, is_signed, extend,
aaa1f954
EI
1003 get_mem_index(s),
1004 iss_valid, iss_srt, iss_sf, iss_ar);
60510aed
PM
1005}
1006
4a08d475
PM
1007/*
1008 * Store from FP register to memory
1009 */
1010static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
1011{
1012 /* This writes the bottom N bits of a 128 bit wide vector to memory */
4a08d475 1013 TCGv_i64 tmp = tcg_temp_new_i64();
90e49638 1014 tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(s, srcidx, MO_64));
4a08d475 1015 if (size < 4) {
aa6489da
PC
1016 tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s),
1017 s->be_data + size);
4a08d475 1018 } else {
aa6489da 1019 bool be = s->be_data == MO_BE;
4a08d475 1020 TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
aa6489da 1021
4a08d475 1022 tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
aa6489da
PC
1023 tcg_gen_qemu_st_i64(tmp, be ? tcg_hiaddr : tcg_addr, get_mem_index(s),
1024 s->be_data | MO_Q);
1025 tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx));
1026 tcg_gen_qemu_st_i64(tmp, be ? tcg_addr : tcg_hiaddr, get_mem_index(s),
1027 s->be_data | MO_Q);
4a08d475
PM
1028 tcg_temp_free_i64(tcg_hiaddr);
1029 }
1030
1031 tcg_temp_free_i64(tmp);
1032}
1033
1034/*
1035 * Load from memory to FP register
1036 */
1037static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
1038{
1039 /* This always zero-extends and writes to a full 128 bit wide vector */
4a08d475
PM
1040 TCGv_i64 tmplo = tcg_temp_new_i64();
1041 TCGv_i64 tmphi;
1042
1043 if (size < 4) {
aa6489da 1044 TCGMemOp memop = s->be_data + size;
4a08d475
PM
1045 tmphi = tcg_const_i64(0);
1046 tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
1047 } else {
aa6489da 1048 bool be = s->be_data == MO_BE;
4a08d475 1049 TCGv_i64 tcg_hiaddr;
aa6489da 1050
4a08d475
PM
1051 tmphi = tcg_temp_new_i64();
1052 tcg_hiaddr = tcg_temp_new_i64();
1053
4a08d475 1054 tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
aa6489da
PC
1055 tcg_gen_qemu_ld_i64(tmplo, be ? tcg_hiaddr : tcg_addr, get_mem_index(s),
1056 s->be_data | MO_Q);
1057 tcg_gen_qemu_ld_i64(tmphi, be ? tcg_addr : tcg_hiaddr, get_mem_index(s),
1058 s->be_data | MO_Q);
4a08d475
PM
1059 tcg_temp_free_i64(tcg_hiaddr);
1060 }
1061
90e49638
PM
1062 tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64));
1063 tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx));
4a08d475
PM
1064
1065 tcg_temp_free_i64(tmplo);
1066 tcg_temp_free_i64(tmphi);
4ff55bcb
RH
1067
1068 clear_vec_high(s, true, destidx);
4a08d475
PM
1069}
1070
72430bf5
AB
1071/*
1072 * Vector load/store helpers.
1073 *
1074 * The principal difference between this and a FP load is that we don't
1075 * zero extend as we are filling a partial chunk of the vector register.
1076 * These functions don't support 128 bit loads/stores, which would be
1077 * normal load/store operations.
a08582f4
PM
1078 *
1079 * The _i32 versions are useful when operating on 32 bit quantities
1080 * (eg for floating point single or using Neon helper functions).
72430bf5
AB
1081 */
1082
1083/* Get value of an element within a vector register */
1084static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
1085 int element, TCGMemOp memop)
1086{
90e49638 1087 int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
72430bf5
AB
1088 switch (memop) {
1089 case MO_8:
1090 tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
1091 break;
1092 case MO_16:
1093 tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
1094 break;
1095 case MO_32:
1096 tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
1097 break;
1098 case MO_8|MO_SIGN:
1099 tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
1100 break;
1101 case MO_16|MO_SIGN:
1102 tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
1103 break;
1104 case MO_32|MO_SIGN:
1105 tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
1106 break;
1107 case MO_64:
1108 case MO_64|MO_SIGN:
1109 tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
1110 break;
1111 default:
1112 g_assert_not_reached();
1113 }
1114}
1115
a08582f4
PM
1116static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
1117 int element, TCGMemOp memop)
1118{
90e49638 1119 int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
a08582f4
PM
1120 switch (memop) {
1121 case MO_8:
1122 tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
1123 break;
1124 case MO_16:
1125 tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off);
1126 break;
1127 case MO_8|MO_SIGN:
1128 tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off);
1129 break;
1130 case MO_16|MO_SIGN:
1131 tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off);
1132 break;
1133 case MO_32:
1134 case MO_32|MO_SIGN:
1135 tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off);
1136 break;
1137 default:
1138 g_assert_not_reached();
1139 }
1140}
1141
72430bf5
AB
1142/* Set value of an element within a vector register */
1143static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
1144 int element, TCGMemOp memop)
1145{
90e49638 1146 int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
72430bf5
AB
1147 switch (memop) {
1148 case MO_8:
1149 tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
1150 break;
1151 case MO_16:
1152 tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
1153 break;
1154 case MO_32:
1155 tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
1156 break;
1157 case MO_64:
1158 tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
1159 break;
1160 default:
1161 g_assert_not_reached();
1162 }
1163}
1164
1f8a73af
PM
1165static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
1166 int destidx, int element, TCGMemOp memop)
1167{
90e49638 1168 int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
1f8a73af
PM
1169 switch (memop) {
1170 case MO_8:
1171 tcg_gen_st8_i32(tcg_src, cpu_env, vect_off);
1172 break;
1173 case MO_16:
1174 tcg_gen_st16_i32(tcg_src, cpu_env, vect_off);
1175 break;
1176 case MO_32:
1177 tcg_gen_st_i32(tcg_src, cpu_env, vect_off);
1178 break;
1179 default:
1180 g_assert_not_reached();
1181 }
1182}
1183
72430bf5
AB
1184/* Store from vector register to memory */
1185static void do_vec_st(DisasContext *s, int srcidx, int element,
87f9a7f0 1186 TCGv_i64 tcg_addr, int size, TCGMemOp endian)
72430bf5 1187{
72430bf5
AB
1188 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
1189
1190 read_vec_element(s, tcg_tmp, srcidx, element, size);
87f9a7f0 1191 tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), endian | size);
72430bf5
AB
1192
1193 tcg_temp_free_i64(tcg_tmp);
1194}
1195
1196/* Load from memory to vector register */
1197static void do_vec_ld(DisasContext *s, int destidx, int element,
87f9a7f0 1198 TCGv_i64 tcg_addr, int size, TCGMemOp endian)
72430bf5 1199{
72430bf5
AB
1200 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
1201
87f9a7f0 1202 tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), endian | size);
72430bf5
AB
1203 write_vec_element(s, tcg_tmp, destidx, element, size);
1204
1205 tcg_temp_free_i64(tcg_tmp);
1206}
1207
8c6afa6a
PM
1208/* Check that FP/Neon access is enabled. If it is, return
1209 * true. If not, emit code to generate an appropriate exception,
1210 * and return false; the caller should not emit any code for
1211 * the instruction. Note that this check must happen after all
1212 * unallocated-encoding checks (otherwise the syndrome information
1213 * for the resulting exception will be incorrect).
1214 */
1215static inline bool fp_access_check(DisasContext *s)
1216{
90e49638
PM
1217 assert(!s->fp_access_checked);
1218 s->fp_access_checked = true;
1219
9dbbc748 1220 if (!s->fp_excp_el) {
8c6afa6a
PM
1221 return true;
1222 }
1223
73710361 1224 gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false),
9dbbc748 1225 s->fp_excp_el);
8c6afa6a
PM
1226 return false;
1227}
1228
490aa7f1
RH
1229/* Check that SVE access is enabled. If it is, return true.
1230 * If not, emit code to generate an appropriate exception and return false.
1231 */
8c71baed 1232bool sve_access_check(DisasContext *s)
490aa7f1
RH
1233{
1234 if (s->sve_excp_el) {
1235 gen_exception_insn(s, 4, EXCP_UDEF, syn_sve_access_trap(),
1236 s->sve_excp_el);
1237 return false;
1238 }
8c71baed 1239 return fp_access_check(s);
490aa7f1
RH
1240}
1241
229b7a05
AB
1242/*
1243 * This utility function is for doing register extension with an
1244 * optional shift. You will likely want to pass a temporary for the
1245 * destination register. See DecodeRegExtend() in the ARM ARM.
1246 */
1247static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
1248 int option, unsigned int shift)
1249{
1250 int extsize = extract32(option, 0, 2);
1251 bool is_signed = extract32(option, 2, 1);
1252
1253 if (is_signed) {
1254 switch (extsize) {
1255 case 0:
1256 tcg_gen_ext8s_i64(tcg_out, tcg_in);
1257 break;
1258 case 1:
1259 tcg_gen_ext16s_i64(tcg_out, tcg_in);
1260 break;
1261 case 2:
1262 tcg_gen_ext32s_i64(tcg_out, tcg_in);
1263 break;
1264 case 3:
1265 tcg_gen_mov_i64(tcg_out, tcg_in);
1266 break;
1267 }
1268 } else {
1269 switch (extsize) {
1270 case 0:
1271 tcg_gen_ext8u_i64(tcg_out, tcg_in);
1272 break;
1273 case 1:
1274 tcg_gen_ext16u_i64(tcg_out, tcg_in);
1275 break;
1276 case 2:
1277 tcg_gen_ext32u_i64(tcg_out, tcg_in);
1278 break;
1279 case 3:
1280 tcg_gen_mov_i64(tcg_out, tcg_in);
1281 break;
1282 }
1283 }
1284
1285 if (shift) {
1286 tcg_gen_shli_i64(tcg_out, tcg_out, shift);
1287 }
1288}
1289
4a08d475
PM
1290static inline void gen_check_sp_alignment(DisasContext *s)
1291{
1292 /* The AArch64 architecture mandates that (if enabled via PSTATE
1293 * or SCTLR bits) there is a check that SP is 16-aligned on every
1294 * SP-relative load or store (with an exception generated if it is not).
1295 * In line with general QEMU practice regarding misaligned accesses,
1296 * we omit these checks for the sake of guest program performance.
1297 * This function is provided as a hook so we can more easily add these
1298 * checks in future (possibly as a "favour catching guest program bugs
1299 * over speed" user selectable option).
1300 */
1301}
1302
384b26fb
AB
1303/*
1304 * This provides a simple table based table lookup decoder. It is
1305 * intended to be used when the relevant bits for decode are too
1306 * awkwardly placed and switch/if based logic would be confusing and
1307 * deeply nested. Since it's a linear search through the table, tables
1308 * should be kept small.
1309 *
1310 * It returns the first handler where insn & mask == pattern, or
1311 * NULL if there is no match.
1312 * The table is terminated by an empty mask (i.e. 0)
1313 */
1314static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
1315 uint32_t insn)
1316{
1317 const AArch64DecodeTable *tptr = table;
1318
1319 while (tptr->mask) {
1320 if ((insn & tptr->mask) == tptr->pattern) {
1321 return tptr->disas_fn;
1322 }
1323 tptr++;
1324 }
1325 return NULL;
1326}
1327
ad7ee8a2 1328/*
4ce31af4
PM
1329 * The instruction disassembly implemented here matches
1330 * the instruction encoding classifications in chapter C4
1331 * of the ARM Architecture Reference Manual (DDI0487B_a);
1332 * classification names and decode diagrams here should generally
1333 * match up with those in the manual.
ad7ee8a2
CF
1334 */
1335
4ce31af4 1336/* Unconditional branch (immediate)
11e169de
AG
1337 * 31 30 26 25 0
1338 * +----+-----------+-------------------------------------+
1339 * | op | 0 0 1 0 1 | imm26 |
1340 * +----+-----------+-------------------------------------+
1341 */
ad7ee8a2
CF
1342static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
1343{
11e169de
AG
1344 uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
1345
1743d55c 1346 if (insn & (1U << 31)) {
4ce31af4 1347 /* BL Branch with link */
11e169de
AG
1348 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
1349 }
1350
4ce31af4 1351 /* B Branch / BL Branch with link */
11e169de 1352 gen_goto_tb(s, 0, addr);
ad7ee8a2
CF
1353}
1354
4ce31af4 1355/* Compare and branch (immediate)
60e53388
AG
1356 * 31 30 25 24 23 5 4 0
1357 * +----+-------------+----+---------------------+--------+
1358 * | sf | 0 1 1 0 1 0 | op | imm19 | Rt |
1359 * +----+-------------+----+---------------------+--------+
1360 */
ad7ee8a2
CF
1361static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
1362{
60e53388
AG
1363 unsigned int sf, op, rt;
1364 uint64_t addr;
42a268c2 1365 TCGLabel *label_match;
60e53388
AG
1366 TCGv_i64 tcg_cmp;
1367
1368 sf = extract32(insn, 31, 1);
1369 op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
1370 rt = extract32(insn, 0, 5);
1371 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
1372
1373 tcg_cmp = read_cpu_reg(s, rt, sf);
1374 label_match = gen_new_label();
1375
1376 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
1377 tcg_cmp, 0, label_match);
1378
1379 gen_goto_tb(s, 0, s->pc);
1380 gen_set_label(label_match);
1381 gen_goto_tb(s, 1, addr);
ad7ee8a2
CF
1382}
1383
4ce31af4 1384/* Test and branch (immediate)
db0f7958
AG
1385 * 31 30 25 24 23 19 18 5 4 0
1386 * +----+-------------+----+-------+-------------+------+
1387 * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
1388 * +----+-------------+----+-------+-------------+------+
1389 */
ad7ee8a2
CF
1390static void disas_test_b_imm(DisasContext *s, uint32_t insn)
1391{
db0f7958
AG
1392 unsigned int bit_pos, op, rt;
1393 uint64_t addr;
42a268c2 1394 TCGLabel *label_match;
db0f7958
AG
1395 TCGv_i64 tcg_cmp;
1396
1397 bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
1398 op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
1399 addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
1400 rt = extract32(insn, 0, 5);
1401
1402 tcg_cmp = tcg_temp_new_i64();
1403 tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
1404 label_match = gen_new_label();
1405 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
1406 tcg_cmp, 0, label_match);
1407 tcg_temp_free_i64(tcg_cmp);
1408 gen_goto_tb(s, 0, s->pc);
1409 gen_set_label(label_match);
1410 gen_goto_tb(s, 1, addr);
ad7ee8a2
CF
1411}
1412
4ce31af4 1413/* Conditional branch (immediate)
39fb730a
AG
1414 * 31 25 24 23 5 4 3 0
1415 * +---------------+----+---------------------+----+------+
1416 * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
1417 * +---------------+----+---------------------+----+------+
1418 */
ad7ee8a2
CF
1419static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
1420{
39fb730a
AG
1421 unsigned int cond;
1422 uint64_t addr;
1423
1424 if ((insn & (1 << 4)) || (insn & (1 << 24))) {
1425 unallocated_encoding(s);
1426 return;
1427 }
1428 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
1429 cond = extract32(insn, 0, 4);
1430
1431 if (cond < 0x0e) {
1432 /* genuinely conditional branches */
42a268c2 1433 TCGLabel *label_match = gen_new_label();
39fb730a
AG
1434 arm_gen_test_cc(cond, label_match);
1435 gen_goto_tb(s, 0, s->pc);
1436 gen_set_label(label_match);
1437 gen_goto_tb(s, 1, addr);
1438 } else {
1439 /* 0xe and 0xf are both "always" conditions */
1440 gen_goto_tb(s, 0, addr);
1441 }
ad7ee8a2
CF
1442}
1443
4ce31af4 1444/* HINT instruction group, including various allocated HINTs */
87462e0f
CF
1445static void handle_hint(DisasContext *s, uint32_t insn,
1446 unsigned int op1, unsigned int op2, unsigned int crm)
1447{
1448 unsigned int selector = crm << 3 | op2;
1449
1450 if (op1 != 3) {
1451 unallocated_encoding(s);
1452 return;
1453 }
1454
1455 switch (selector) {
7c94c834
RH
1456 case 0b00000: /* NOP */
1457 break;
1458 case 0b00011: /* WFI */
dcba3a8d 1459 s->base.is_jmp = DISAS_WFI;
7c94c834
RH
1460 break;
1461 case 0b00001: /* YIELD */
2399d4e7
EC
1462 /* When running in MTTCG we don't generate jumps to the yield and
1463 * WFE helpers as it won't affect the scheduling of other vCPUs.
1464 * If we wanted to more completely model WFE/SEV so we don't busy
1465 * spin unnecessarily we would need to do something more involved.
1466 */
2399d4e7 1467 if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
dcba3a8d 1468 s->base.is_jmp = DISAS_YIELD;
c22edfeb 1469 }
7c94c834
RH
1470 break;
1471 case 0b00010: /* WFE */
2399d4e7 1472 if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
dcba3a8d 1473 s->base.is_jmp = DISAS_WFE;
c22edfeb 1474 }
7c94c834
RH
1475 break;
1476 case 0b00100: /* SEV */
1477 case 0b00101: /* SEVL */
87462e0f 1478 /* we treat all as NOP at least for now */
7c94c834
RH
1479 break;
1480 case 0b00111: /* XPACLRI */
1481 if (s->pauth_active) {
1482 gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]);
1483 }
1484 break;
1485 case 0b01000: /* PACIA1716 */
1486 if (s->pauth_active) {
1487 gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1488 }
1489 break;
1490 case 0b01010: /* PACIB1716 */
1491 if (s->pauth_active) {
1492 gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1493 }
1494 break;
1495 case 0b01100: /* AUTIA1716 */
1496 if (s->pauth_active) {
1497 gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1498 }
1499 break;
1500 case 0b01110: /* AUTIB1716 */
1501 if (s->pauth_active) {
1502 gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1503 }
1504 break;
1505 case 0b11000: /* PACIAZ */
1506 if (s->pauth_active) {
1507 gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],
1508 new_tmp_a64_zero(s));
1509 }
1510 break;
1511 case 0b11001: /* PACIASP */
1512 if (s->pauth_active) {
1513 gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1514 }
1515 break;
1516 case 0b11010: /* PACIBZ */
1517 if (s->pauth_active) {
1518 gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30],
1519 new_tmp_a64_zero(s));
1520 }
1521 break;
1522 case 0b11011: /* PACIBSP */
1523 if (s->pauth_active) {
1524 gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1525 }
1526 break;
1527 case 0b11100: /* AUTIAZ */
1528 if (s->pauth_active) {
1529 gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30],
1530 new_tmp_a64_zero(s));
1531 }
1532 break;
1533 case 0b11101: /* AUTIASP */
1534 if (s->pauth_active) {
1535 gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1536 }
1537 break;
1538 case 0b11110: /* AUTIBZ */
1539 if (s->pauth_active) {
1540 gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30],
1541 new_tmp_a64_zero(s));
1542 }
1543 break;
1544 case 0b11111: /* AUTIBSP */
1545 if (s->pauth_active) {
1546 gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1547 }
1548 break;
87462e0f
CF
1549 default:
1550 /* default specified as NOP equivalent */
7c94c834 1551 break;
87462e0f
CF
1552 }
1553}
1554
fa2ef212
MM
1555static void gen_clrex(DisasContext *s, uint32_t insn)
1556{
1557 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
1558}
1559
87462e0f
CF
1560/* CLREX, DSB, DMB, ISB */
1561static void handle_sync(DisasContext *s, uint32_t insn,
1562 unsigned int op1, unsigned int op2, unsigned int crm)
1563{
ce1bd93f
PK
1564 TCGBar bar;
1565
87462e0f
CF
1566 if (op1 != 3) {
1567 unallocated_encoding(s);
1568 return;
1569 }
1570
1571 switch (op2) {
1572 case 2: /* CLREX */
fa2ef212 1573 gen_clrex(s, insn);
87462e0f
CF
1574 return;
1575 case 4: /* DSB */
1576 case 5: /* DMB */
ce1bd93f
PK
1577 switch (crm & 3) {
1578 case 1: /* MBReqTypes_Reads */
1579 bar = TCG_BAR_SC | TCG_MO_LD_LD | TCG_MO_LD_ST;
1580 break;
1581 case 2: /* MBReqTypes_Writes */
1582 bar = TCG_BAR_SC | TCG_MO_ST_ST;
1583 break;
1584 default: /* MBReqTypes_All */
1585 bar = TCG_BAR_SC | TCG_MO_ALL;
1586 break;
1587 }
1588 tcg_gen_mb(bar);
87462e0f 1589 return;
6df99dec
SS
1590 case 6: /* ISB */
1591 /* We need to break the TB after this insn to execute
1592 * a self-modified code correctly and also to take
1593 * any pending interrupts immediately.
1594 */
0b609cc1 1595 gen_goto_tb(s, 0, s->pc);
6df99dec 1596 return;
87462e0f
CF
1597 default:
1598 unallocated_encoding(s);
1599 return;
1600 }
1601}
1602
4ce31af4 1603/* MSR (immediate) - move immediate to processor state field */
87462e0f
CF
1604static void handle_msr_i(DisasContext *s, uint32_t insn,
1605 unsigned int op1, unsigned int op2, unsigned int crm)
1606{
9cfa0b4e
PM
1607 int op = op1 << 3 | op2;
1608 switch (op) {
1609 case 0x05: /* SPSel */
dcbff19b 1610 if (s->current_el == 0) {
9cfa0b4e
PM
1611 unallocated_encoding(s);
1612 return;
1613 }
1614 /* fall through */
1615 case 0x1e: /* DAIFSet */
1616 case 0x1f: /* DAIFClear */
1617 {
1618 TCGv_i32 tcg_imm = tcg_const_i32(crm);
1619 TCGv_i32 tcg_op = tcg_const_i32(op);
1620 gen_a64_set_pc_im(s->pc - 4);
1621 gen_helper_msr_i_pstate(cpu_env, tcg_op, tcg_imm);
1622 tcg_temp_free_i32(tcg_imm);
1623 tcg_temp_free_i32(tcg_op);
8da54b25
RH
1624 /* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
1625 gen_a64_set_pc_im(s->pc);
dcba3a8d 1626 s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
9cfa0b4e
PM
1627 break;
1628 }
1629 default:
1630 unallocated_encoding(s);
1631 return;
1632 }
87462e0f
CF
1633}
1634
b0d2b7d0
PM
1635static void gen_get_nzcv(TCGv_i64 tcg_rt)
1636{
1637 TCGv_i32 tmp = tcg_temp_new_i32();
1638 TCGv_i32 nzcv = tcg_temp_new_i32();
1639
1640 /* build bit 31, N */
1743d55c 1641 tcg_gen_andi_i32(nzcv, cpu_NF, (1U << 31));
b0d2b7d0
PM
1642 /* build bit 30, Z */
1643 tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
1644 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
1645 /* build bit 29, C */
1646 tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
1647 /* build bit 28, V */
1648 tcg_gen_shri_i32(tmp, cpu_VF, 31);
1649 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
1650 /* generate result */
1651 tcg_gen_extu_i32_i64(tcg_rt, nzcv);
1652
1653 tcg_temp_free_i32(nzcv);
1654 tcg_temp_free_i32(tmp);
1655}
1656
1657static void gen_set_nzcv(TCGv_i64 tcg_rt)
1658
1659{
1660 TCGv_i32 nzcv = tcg_temp_new_i32();
1661
1662 /* take NZCV from R[t] */
ecc7b3aa 1663 tcg_gen_extrl_i64_i32(nzcv, tcg_rt);
b0d2b7d0
PM
1664
1665 /* bit 31, N */
1743d55c 1666 tcg_gen_andi_i32(cpu_NF, nzcv, (1U << 31));
b0d2b7d0
PM
1667 /* bit 30, Z */
1668 tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
1669 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
1670 /* bit 29, C */
1671 tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
1672 tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
1673 /* bit 28, V */
1674 tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
1675 tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
1676 tcg_temp_free_i32(nzcv);
1677}
1678
4ce31af4
PM
1679/* MRS - move from system register
1680 * MSR (register) - move to system register
1681 * SYS
1682 * SYSL
fea50522
PM
1683 * These are all essentially the same insn in 'read' and 'write'
1684 * versions, with varying op0 fields.
1685 */
1686static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
1687 unsigned int op0, unsigned int op1, unsigned int op2,
87462e0f
CF
1688 unsigned int crn, unsigned int crm, unsigned int rt)
1689{
fea50522
PM
1690 const ARMCPRegInfo *ri;
1691 TCGv_i64 tcg_rt;
87462e0f 1692
fea50522
PM
1693 ri = get_arm_cp_reginfo(s->cp_regs,
1694 ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
1695 crn, crm, op0, op1, op2));
87462e0f 1696
fea50522 1697 if (!ri) {
626187d8
PM
1698 /* Unknown register; this might be a guest error or a QEMU
1699 * unimplemented feature.
1700 */
1701 qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 "
1702 "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n",
1703 isread ? "read" : "write", op0, op1, crn, crm, op2);
fea50522
PM
1704 unallocated_encoding(s);
1705 return;
1706 }
1707
1708 /* Check access permissions */
dcbff19b 1709 if (!cp_access_ok(s->current_el, ri, isread)) {
fea50522
PM
1710 unallocated_encoding(s);
1711 return;
1712 }
1713
f59df3f2
PM
1714 if (ri->accessfn) {
1715 /* Emit code to perform further access permissions checks at
1716 * runtime; this may result in an exception.
1717 */
1718 TCGv_ptr tmpptr;
3f208fd7 1719 TCGv_i32 tcg_syn, tcg_isread;
8bcbf37c
PM
1720 uint32_t syndrome;
1721
f59df3f2
PM
1722 gen_a64_set_pc_im(s->pc - 4);
1723 tmpptr = tcg_const_ptr(ri);
8bcbf37c
PM
1724 syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
1725 tcg_syn = tcg_const_i32(syndrome);
3f208fd7
PM
1726 tcg_isread = tcg_const_i32(isread);
1727 gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, tcg_isread);
f59df3f2 1728 tcg_temp_free_ptr(tmpptr);
8bcbf37c 1729 tcg_temp_free_i32(tcg_syn);
3f208fd7 1730 tcg_temp_free_i32(tcg_isread);
f59df3f2
PM
1731 }
1732
fea50522
PM
1733 /* Handle special cases first */
1734 switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
1735 case ARM_CP_NOP:
1736 return;
b0d2b7d0
PM
1737 case ARM_CP_NZCV:
1738 tcg_rt = cpu_reg(s, rt);
1739 if (isread) {
1740 gen_get_nzcv(tcg_rt);
1741 } else {
1742 gen_set_nzcv(tcg_rt);
1743 }
1744 return;
0eef9d98
PM
1745 case ARM_CP_CURRENTEL:
1746 /* Reads as current EL value from pstate, which is
1747 * guaranteed to be constant by the tb flags.
1748 */
1749 tcg_rt = cpu_reg(s, rt);
dcbff19b 1750 tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
0eef9d98 1751 return;
aca3f40b
PM
1752 case ARM_CP_DC_ZVA:
1753 /* Writes clear the aligned block of memory which rt points into. */
1754 tcg_rt = cpu_reg(s, rt);
1755 gen_helper_dc_zva(cpu_env, tcg_rt);
1756 return;
fea50522
PM
1757 default:
1758 break;
1759 }
fe03d45f
RH
1760 if ((ri->type & ARM_CP_FPU) && !fp_access_check(s)) {
1761 return;
11d7870b
RH
1762 } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
1763 return;
fe03d45f 1764 }
fea50522 1765
c5a49c63 1766 if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
fea50522
PM
1767 gen_io_start();
1768 }
1769
1770 tcg_rt = cpu_reg(s, rt);
1771
1772 if (isread) {
1773 if (ri->type & ARM_CP_CONST) {
1774 tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
1775 } else if (ri->readfn) {
1776 TCGv_ptr tmpptr;
fea50522
PM
1777 tmpptr = tcg_const_ptr(ri);
1778 gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr);
1779 tcg_temp_free_ptr(tmpptr);
1780 } else {
1781 tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
1782 }
1783 } else {
1784 if (ri->type & ARM_CP_CONST) {
1785 /* If not forbidden by access permissions, treat as WI */
1786 return;
1787 } else if (ri->writefn) {
1788 TCGv_ptr tmpptr;
fea50522
PM
1789 tmpptr = tcg_const_ptr(ri);
1790 gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt);
1791 tcg_temp_free_ptr(tmpptr);
1792 } else {
1793 tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
1794 }
1795 }
1796
c5a49c63 1797 if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
fea50522
PM
1798 /* I/O operations must end the TB here (whether read or write) */
1799 gen_io_end();
dcba3a8d 1800 s->base.is_jmp = DISAS_UPDATE;
fea50522
PM
1801 } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
1802 /* We default to ending the TB on a coprocessor register write,
1803 * but allow this to be suppressed by the register definition
1804 * (usually only necessary to work around guest bugs).
1805 */
dcba3a8d 1806 s->base.is_jmp = DISAS_UPDATE;
fea50522 1807 }
ad7ee8a2
CF
1808}
1809
4ce31af4 1810/* System
87462e0f
CF
1811 * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
1812 * +---------------------+---+-----+-----+-------+-------+-----+------+
1813 * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
1814 * +---------------------+---+-----+-----+-------+-------+-----+------+
1815 */
1816static void disas_system(DisasContext *s, uint32_t insn)
1817{
1818 unsigned int l, op0, op1, crn, crm, op2, rt;
1819 l = extract32(insn, 21, 1);
1820 op0 = extract32(insn, 19, 2);
1821 op1 = extract32(insn, 16, 3);
1822 crn = extract32(insn, 12, 4);
1823 crm = extract32(insn, 8, 4);
1824 op2 = extract32(insn, 5, 3);
1825 rt = extract32(insn, 0, 5);
1826
1827 if (op0 == 0) {
1828 if (l || rt != 31) {
1829 unallocated_encoding(s);
1830 return;
1831 }
1832 switch (crn) {
4ce31af4 1833 case 2: /* HINT (including allocated hints like NOP, YIELD, etc) */
87462e0f
CF
1834 handle_hint(s, insn, op1, op2, crm);
1835 break;
1836 case 3: /* CLREX, DSB, DMB, ISB */
1837 handle_sync(s, insn, op1, op2, crm);
1838 break;
4ce31af4 1839 case 4: /* MSR (immediate) */
87462e0f
CF
1840 handle_msr_i(s, insn, op1, op2, crm);
1841 break;
1842 default:
1843 unallocated_encoding(s);
1844 break;
1845 }
1846 return;
1847 }
fea50522 1848 handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
87462e0f
CF
1849}
1850
4ce31af4 1851/* Exception generation
9618e809
AG
1852 *
1853 * 31 24 23 21 20 5 4 2 1 0
1854 * +-----------------+-----+------------------------+-----+----+
1855 * | 1 1 0 1 0 1 0 0 | opc | imm16 | op2 | LL |
1856 * +-----------------------+------------------------+----------+
1857 */
ad7ee8a2
CF
1858static void disas_exc(DisasContext *s, uint32_t insn)
1859{
9618e809
AG
1860 int opc = extract32(insn, 21, 3);
1861 int op2_ll = extract32(insn, 0, 5);
d4a2dc67 1862 int imm16 = extract32(insn, 5, 16);
e0d6e6a5 1863 TCGv_i32 tmp;
9618e809
AG
1864
1865 switch (opc) {
1866 case 0:
7ea47fe7
PM
1867 /* For SVC, HVC and SMC we advance the single-step state
1868 * machine before taking the exception. This is architecturally
1869 * mandated, to ensure that single-stepping a system call
1870 * instruction works properly.
1871 */
35979d71 1872 switch (op2_ll) {
957956b3 1873 case 1: /* SVC */
35979d71 1874 gen_ss_advance(s);
73710361
GB
1875 gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16),
1876 default_exception_el(s));
35979d71 1877 break;
957956b3 1878 case 2: /* HVC */
dcbff19b 1879 if (s->current_el == 0) {
35979d71
EI
1880 unallocated_encoding(s);
1881 break;
1882 }
1883 /* The pre HVC helper handles cases when HVC gets trapped
1884 * as an undefined insn by runtime configuration.
1885 */
1886 gen_a64_set_pc_im(s->pc - 4);
1887 gen_helper_pre_hvc(cpu_env);
1888 gen_ss_advance(s);
73710361 1889 gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16), 2);
35979d71 1890 break;
957956b3 1891 case 3: /* SMC */
dcbff19b 1892 if (s->current_el == 0) {
e0d6e6a5
EI
1893 unallocated_encoding(s);
1894 break;
1895 }
1896 gen_a64_set_pc_im(s->pc - 4);
1897 tmp = tcg_const_i32(syn_aa64_smc(imm16));
1898 gen_helper_pre_smc(cpu_env, tmp);
1899 tcg_temp_free_i32(tmp);
1900 gen_ss_advance(s);
73710361 1901 gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16), 3);
e0d6e6a5 1902 break;
35979d71
EI
1903 default:
1904 unallocated_encoding(s);
1905 break;
1906 }
9618e809
AG
1907 break;
1908 case 1:
1909 if (op2_ll != 0) {
1910 unallocated_encoding(s);
1911 break;
1912 }
1913 /* BRK */
c900a2e6 1914 gen_exception_bkpt_insn(s, 4, syn_aa64_bkpt(imm16));
9618e809
AG
1915 break;
1916 case 2:
1917 if (op2_ll != 0) {
1918 unallocated_encoding(s);
1919 break;
1920 }
8012c84f
PM
1921 /* HLT. This has two purposes.
1922 * Architecturally, it is an external halting debug instruction.
1923 * Since QEMU doesn't implement external debug, we treat this as
1924 * it is required for halting debug disabled: it will UNDEF.
1925 * Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
1926 */
1927 if (semihosting_enabled() && imm16 == 0xf000) {
1928#ifndef CONFIG_USER_ONLY
1929 /* In system mode, don't allow userspace access to semihosting,
1930 * to provide some semblance of security (and for consistency
1931 * with our 32-bit semihosting).
1932 */
1933 if (s->current_el == 0) {
1934 unsupported_encoding(s, insn);
1935 break;
1936 }
1937#endif
1938 gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
1939 } else {
1940 unsupported_encoding(s, insn);
1941 }
9618e809
AG
1942 break;
1943 case 5:
1944 if (op2_ll < 1 || op2_ll > 3) {
1945 unallocated_encoding(s);
1946 break;
1947 }
1948 /* DCPS1, DCPS2, DCPS3 */
1949 unsupported_encoding(s, insn);
1950 break;
1951 default:
1952 unallocated_encoding(s);
1953 break;
1954 }
ad7ee8a2
CF
1955}
1956
4ce31af4 1957/* Unconditional branch (register)
b001c8c3
AG
1958 * 31 25 24 21 20 16 15 10 9 5 4 0
1959 * +---------------+-------+-------+-------+------+-------+
1960 * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
1961 * +---------------+-------+-------+-------+------+-------+
1962 */
ad7ee8a2
CF
1963static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
1964{
b001c8c3 1965 unsigned int opc, op2, op3, rn, op4;
d9f482a0 1966 TCGv_i64 dst;
561c0a33 1967 TCGv_i64 modifier;
b001c8c3
AG
1968
1969 opc = extract32(insn, 21, 4);
1970 op2 = extract32(insn, 16, 5);
1971 op3 = extract32(insn, 10, 6);
1972 rn = extract32(insn, 5, 5);
1973 op4 = extract32(insn, 0, 5);
1974
f7cf3bfc
RH
1975 if (op2 != 0x1f) {
1976 goto do_unallocated;
b001c8c3
AG
1977 }
1978
1979 switch (opc) {
1980 case 0: /* BR */
b001c8c3 1981 case 1: /* BLR */
6feecb8b 1982 case 2: /* RET */
f7cf3bfc
RH
1983 switch (op3) {
1984 case 0:
561c0a33 1985 /* BR, BLR, RET */
f7cf3bfc
RH
1986 if (op4 != 0) {
1987 goto do_unallocated;
1988 }
1989 dst = cpu_reg(s, rn);
1990 break;
1991
561c0a33
RH
1992 case 2:
1993 case 3:
1994 if (!dc_isar_feature(aa64_pauth, s)) {
1995 goto do_unallocated;
1996 }
1997 if (opc == 2) {
1998 /* RETAA, RETAB */
1999 if (rn != 0x1f || op4 != 0x1f) {
2000 goto do_unallocated;
2001 }
2002 rn = 30;
2003 modifier = cpu_X[31];
2004 } else {
2005 /* BRAAZ, BRABZ, BLRAAZ, BLRABZ */
2006 if (op4 != 0x1f) {
2007 goto do_unallocated;
2008 }
2009 modifier = new_tmp_a64_zero(s);
2010 }
2011 if (s->pauth_active) {
2012 dst = new_tmp_a64(s);
2013 if (op3 == 2) {
2014 gen_helper_autia(dst, cpu_env, cpu_reg(s, rn), modifier);
2015 } else {
2016 gen_helper_autib(dst, cpu_env, cpu_reg(s, rn), modifier);
2017 }
2018 } else {
2019 dst = cpu_reg(s, rn);
2020 }
2021 break;
2022
f7cf3bfc
RH
2023 default:
2024 goto do_unallocated;
2025 }
2026
2027 gen_a64_set_pc(s, dst);
6feecb8b
TH
2028 /* BLR also needs to load return address */
2029 if (opc == 1) {
2030 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
2031 }
b001c8c3 2032 break;
f7cf3bfc 2033
561c0a33
RH
2034 case 8: /* BRAA */
2035 case 9: /* BLRAA */
2036 if (!dc_isar_feature(aa64_pauth, s)) {
2037 goto do_unallocated;
2038 }
2039 if (op3 != 2 || op3 != 3) {
2040 goto do_unallocated;
2041 }
2042 if (s->pauth_active) {
2043 dst = new_tmp_a64(s);
2044 modifier = cpu_reg_sp(s, op4);
2045 if (op3 == 2) {
2046 gen_helper_autia(dst, cpu_env, cpu_reg(s, rn), modifier);
2047 } else {
2048 gen_helper_autib(dst, cpu_env, cpu_reg(s, rn), modifier);
2049 }
2050 } else {
2051 dst = cpu_reg(s, rn);
2052 }
2053 gen_a64_set_pc(s, dst);
2054 /* BLRAA also needs to load return address */
2055 if (opc == 9) {
2056 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
2057 }
2058 break;
2059
b001c8c3 2060 case 4: /* ERET */
dcbff19b 2061 if (s->current_el == 0) {
f7cf3bfc
RH
2062 goto do_unallocated;
2063 }
2064 switch (op3) {
561c0a33 2065 case 0: /* ERET */
f7cf3bfc
RH
2066 if (op4 != 0) {
2067 goto do_unallocated;
2068 }
2069 dst = tcg_temp_new_i64();
2070 tcg_gen_ld_i64(dst, cpu_env,
2071 offsetof(CPUARMState, elr_el[s->current_el]));
2072 break;
2073
561c0a33
RH
2074 case 2: /* ERETAA */
2075 case 3: /* ERETAB */
2076 if (!dc_isar_feature(aa64_pauth, s)) {
2077 goto do_unallocated;
2078 }
2079 if (rn != 0x1f || op4 != 0x1f) {
2080 goto do_unallocated;
2081 }
2082 dst = tcg_temp_new_i64();
2083 tcg_gen_ld_i64(dst, cpu_env,
2084 offsetof(CPUARMState, elr_el[s->current_el]));
2085 if (s->pauth_active) {
2086 modifier = cpu_X[31];
2087 if (op3 == 2) {
2088 gen_helper_autia(dst, cpu_env, dst, modifier);
2089 } else {
2090 gen_helper_autib(dst, cpu_env, dst, modifier);
2091 }
2092 }
2093 break;
2094
f7cf3bfc
RH
2095 default:
2096 goto do_unallocated;
14c521d4 2097 }
e69ad9df
AL
2098 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
2099 gen_io_start();
2100 }
f7cf3bfc 2101
d9f482a0
RH
2102 gen_helper_exception_return(cpu_env, dst);
2103 tcg_temp_free_i64(dst);
e69ad9df
AL
2104 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
2105 gen_io_end();
2106 }
b29fd33d 2107 /* Must exit loop to check un-masked IRQs */
dcba3a8d 2108 s->base.is_jmp = DISAS_EXIT;
52e60cdd 2109 return;
f7cf3bfc 2110
b001c8c3 2111 case 5: /* DRPS */
f7cf3bfc
RH
2112 if (op3 != 0 || op4 != 0 || rn != 0x1f) {
2113 goto do_unallocated;
b001c8c3
AG
2114 } else {
2115 unsupported_encoding(s, insn);
2116 }
2117 return;
f7cf3bfc 2118
b001c8c3 2119 default:
f7cf3bfc 2120 do_unallocated:
b001c8c3
AG
2121 unallocated_encoding(s);
2122 return;
2123 }
2124
dcba3a8d 2125 s->base.is_jmp = DISAS_JUMP;
ad7ee8a2
CF
2126}
2127
4ce31af4 2128/* Branches, exception generating and system instructions */
ad7ee8a2
CF
2129static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
2130{
2131 switch (extract32(insn, 25, 7)) {
2132 case 0x0a: case 0x0b:
2133 case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
2134 disas_uncond_b_imm(s, insn);
2135 break;
2136 case 0x1a: case 0x5a: /* Compare & branch (immediate) */
2137 disas_comp_b_imm(s, insn);
2138 break;
2139 case 0x1b: case 0x5b: /* Test & branch (immediate) */
2140 disas_test_b_imm(s, insn);
2141 break;
2142 case 0x2a: /* Conditional branch (immediate) */
2143 disas_cond_b_imm(s, insn);
2144 break;
2145 case 0x6a: /* Exception generation / System */
2146 if (insn & (1 << 24)) {
08d5e3bd
PM
2147 if (extract32(insn, 22, 2) == 0) {
2148 disas_system(s, insn);
2149 } else {
2150 unallocated_encoding(s);
2151 }
ad7ee8a2
CF
2152 } else {
2153 disas_exc(s, insn);
2154 }
2155 break;
2156 case 0x6b: /* Unconditional branch (register) */
2157 disas_uncond_b_reg(s, insn);
2158 break;
2159 default:
2160 unallocated_encoding(s);
2161 break;
2162 }
2163}
2164
5460da50
AB
2165/*
2166 * Load/Store exclusive instructions are implemented by remembering
2167 * the value/address loaded, and seeing if these are the same
2168 * when the store is performed. This is not actually the architecturally
2169 * mandated semantics, but it works for typical guest code sequences
2170 * and avoids having to monitor regular stores.
2171 *
2172 * The store exclusive uses the atomic cmpxchg primitives to avoid
2173 * races in multi-threaded linux-user and when MTTCG softmmu is
2174 * enabled.
2175 */
fa2ef212
MM
2176static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
2177 TCGv_i64 addr, int size, bool is_pair)
2178{
19514cde
RH
2179 int idx = get_mem_index(s);
2180 TCGMemOp memop = s->be_data;
fa2ef212
MM
2181
2182 g_assert(size <= 3);
fa2ef212 2183 if (is_pair) {
5460da50 2184 g_assert(size >= 2);
19514cde
RH
2185 if (size == 2) {
2186 /* The pair must be single-copy atomic for the doubleword. */
4a2fdb78 2187 memop |= MO_64 | MO_ALIGN;
19514cde
RH
2188 tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
2189 if (s->be_data == MO_LE) {
2190 tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 0, 32);
2191 tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 32, 32);
2192 } else {
2193 tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 32, 32);
2194 tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 0, 32);
2195 }
2196 } else {
4a2fdb78
AF
2197 /* The pair must be single-copy atomic for *each* doubleword, not
2198 the entire quadword, however it must be quadword aligned. */
19514cde 2199 memop |= MO_64;
4a2fdb78
AF
2200 tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx,
2201 memop | MO_ALIGN_16);
19514cde
RH
2202
2203 TCGv_i64 addr2 = tcg_temp_new_i64();
2204 tcg_gen_addi_i64(addr2, addr, 8);
2205 tcg_gen_qemu_ld_i64(cpu_exclusive_high, addr2, idx, memop);
2206 tcg_temp_free_i64(addr2);
2207
2208 tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
2209 tcg_gen_mov_i64(cpu_reg(s, rt2), cpu_exclusive_high);
2210 }
2211 } else {
4a2fdb78 2212 memop |= size | MO_ALIGN;
19514cde
RH
2213 tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
2214 tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
fa2ef212 2215 }
fa2ef212
MM
2216 tcg_gen_mov_i64(cpu_exclusive_addr, addr);
2217}
2218
fa2ef212 2219static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
37e29a64 2220 TCGv_i64 addr, int size, int is_pair)
fa2ef212 2221{
d324b36a
PM
2222 /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]
2223 * && (!is_pair || env->exclusive_high == [addr + datasize])) {
2224 * [addr] = {Rt};
2225 * if (is_pair) {
2226 * [addr + datasize] = {Rt2};
2227 * }
2228 * {Rd} = 0;
2229 * } else {
2230 * {Rd} = 1;
2231 * }
2232 * env->exclusive_addr = -1;
2233 */
42a268c2
RH
2234 TCGLabel *fail_label = gen_new_label();
2235 TCGLabel *done_label = gen_new_label();
d324b36a
PM
2236 TCGv_i64 tmp;
2237
d324b36a
PM
2238 tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
2239
2240 tmp = tcg_temp_new_i64();
d324b36a 2241 if (is_pair) {
1dd089d0 2242 if (size == 2) {
19514cde
RH
2243 if (s->be_data == MO_LE) {
2244 tcg_gen_concat32_i64(tmp, cpu_reg(s, rt), cpu_reg(s, rt2));
2245 } else {
2246 tcg_gen_concat32_i64(tmp, cpu_reg(s, rt2), cpu_reg(s, rt));
2247 }
37e29a64
RH
2248 tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr,
2249 cpu_exclusive_val, tmp,
1dd089d0 2250 get_mem_index(s),
955fd0ad 2251 MO_64 | MO_ALIGN | s->be_data);
19514cde 2252 tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
62823083
RH
2253 } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
2254 if (!HAVE_CMPXCHG128) {
2255 gen_helper_exit_atomic(cpu_env);
2256 s->base.is_jmp = DISAS_NORETURN;
2257 } else if (s->be_data == MO_LE) {
2399d4e7
EC
2258 gen_helper_paired_cmpxchg64_le_parallel(tmp, cpu_env,
2259 cpu_exclusive_addr,
2260 cpu_reg(s, rt),
2261 cpu_reg(s, rt2));
2262 } else {
2399d4e7
EC
2263 gen_helper_paired_cmpxchg64_be_parallel(tmp, cpu_env,
2264 cpu_exclusive_addr,
2265 cpu_reg(s, rt),
2266 cpu_reg(s, rt2));
2399d4e7 2267 }
62823083
RH
2268 } else if (s->be_data == MO_LE) {
2269 gen_helper_paired_cmpxchg64_le(tmp, cpu_env, cpu_exclusive_addr,
2270 cpu_reg(s, rt), cpu_reg(s, rt2));
2271 } else {
2272 gen_helper_paired_cmpxchg64_be(tmp, cpu_env, cpu_exclusive_addr,
2273 cpu_reg(s, rt), cpu_reg(s, rt2));
1dd089d0
EC
2274 }
2275 } else {
37e29a64
RH
2276 tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr, cpu_exclusive_val,
2277 cpu_reg(s, rt), get_mem_index(s),
1dd089d0
EC
2278 size | MO_ALIGN | s->be_data);
2279 tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
d324b36a 2280 }
1dd089d0
EC
2281 tcg_gen_mov_i64(cpu_reg(s, rd), tmp);
2282 tcg_temp_free_i64(tmp);
d324b36a 2283 tcg_gen_br(done_label);
1dd089d0 2284
d324b36a
PM
2285 gen_set_label(fail_label);
2286 tcg_gen_movi_i64(cpu_reg(s, rd), 1);
2287 gen_set_label(done_label);
2288 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
fa2ef212 2289}
fa2ef212 2290
44ac14b0
RH
2291static void gen_compare_and_swap(DisasContext *s, int rs, int rt,
2292 int rn, int size)
2293{
2294 TCGv_i64 tcg_rs = cpu_reg(s, rs);
2295 TCGv_i64 tcg_rt = cpu_reg(s, rt);
2296 int memidx = get_mem_index(s);
2297 TCGv_i64 addr = cpu_reg_sp(s, rn);
2298
2299 if (rn == 31) {
2300 gen_check_sp_alignment(s);
2301 }
2302 tcg_gen_atomic_cmpxchg_i64(tcg_rs, addr, tcg_rs, tcg_rt, memidx,
2303 size | MO_ALIGN | s->be_data);
2304}
2305
2306static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
2307 int rn, int size)
2308{
2309 TCGv_i64 s1 = cpu_reg(s, rs);
2310 TCGv_i64 s2 = cpu_reg(s, rs + 1);
2311 TCGv_i64 t1 = cpu_reg(s, rt);
2312 TCGv_i64 t2 = cpu_reg(s, rt + 1);
2313 TCGv_i64 addr = cpu_reg_sp(s, rn);
2314 int memidx = get_mem_index(s);
2315
2316 if (rn == 31) {
2317 gen_check_sp_alignment(s);
2318 }
2319
2320 if (size == 2) {
2321 TCGv_i64 cmp = tcg_temp_new_i64();
2322 TCGv_i64 val = tcg_temp_new_i64();
2323
2324 if (s->be_data == MO_LE) {
2325 tcg_gen_concat32_i64(val, t1, t2);
2326 tcg_gen_concat32_i64(cmp, s1, s2);
2327 } else {
2328 tcg_gen_concat32_i64(val, t2, t1);
2329 tcg_gen_concat32_i64(cmp, s2, s1);
2330 }
2331
2332 tcg_gen_atomic_cmpxchg_i64(cmp, addr, cmp, val, memidx,
2333 MO_64 | MO_ALIGN | s->be_data);
2334 tcg_temp_free_i64(val);
2335
2336 if (s->be_data == MO_LE) {
2337 tcg_gen_extr32_i64(s1, s2, cmp);
2338 } else {
2339 tcg_gen_extr32_i64(s2, s1, cmp);
2340 }
2341 tcg_temp_free_i64(cmp);
2342 } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
62823083
RH
2343 if (HAVE_CMPXCHG128) {
2344 TCGv_i32 tcg_rs = tcg_const_i32(rs);
2345 if (s->be_data == MO_LE) {
2346 gen_helper_casp_le_parallel(cpu_env, tcg_rs, addr, t1, t2);
2347 } else {
2348 gen_helper_casp_be_parallel(cpu_env, tcg_rs, addr, t1, t2);
2349 }
2350 tcg_temp_free_i32(tcg_rs);
44ac14b0 2351 } else {
62823083
RH
2352 gen_helper_exit_atomic(cpu_env);
2353 s->base.is_jmp = DISAS_NORETURN;
44ac14b0 2354 }
44ac14b0
RH
2355 } else {
2356 TCGv_i64 d1 = tcg_temp_new_i64();
2357 TCGv_i64 d2 = tcg_temp_new_i64();
2358 TCGv_i64 a2 = tcg_temp_new_i64();
2359 TCGv_i64 c1 = tcg_temp_new_i64();
2360 TCGv_i64 c2 = tcg_temp_new_i64();
2361 TCGv_i64 zero = tcg_const_i64(0);
2362
2363 /* Load the two words, in memory order. */
2364 tcg_gen_qemu_ld_i64(d1, addr, memidx,
2365 MO_64 | MO_ALIGN_16 | s->be_data);
2366 tcg_gen_addi_i64(a2, addr, 8);
2367 tcg_gen_qemu_ld_i64(d2, addr, memidx, MO_64 | s->be_data);
2368
2369 /* Compare the two words, also in memory order. */
2370 tcg_gen_setcond_i64(TCG_COND_EQ, c1, d1, s1);
2371 tcg_gen_setcond_i64(TCG_COND_EQ, c2, d2, s2);
2372 tcg_gen_and_i64(c2, c2, c1);
2373
2374 /* If compare equal, write back new data, else write back old data. */
2375 tcg_gen_movcond_i64(TCG_COND_NE, c1, c2, zero, t1, d1);
2376 tcg_gen_movcond_i64(TCG_COND_NE, c2, c2, zero, t2, d2);
2377 tcg_gen_qemu_st_i64(c1, addr, memidx, MO_64 | s->be_data);
2378 tcg_gen_qemu_st_i64(c2, a2, memidx, MO_64 | s->be_data);
2379 tcg_temp_free_i64(a2);
2380 tcg_temp_free_i64(c1);
2381 tcg_temp_free_i64(c2);
2382 tcg_temp_free_i64(zero);
2383
2384 /* Write back the data from memory to Rs. */
2385 tcg_gen_mov_i64(s1, d1);
2386 tcg_gen_mov_i64(s2, d2);
2387 tcg_temp_free_i64(d1);
2388 tcg_temp_free_i64(d2);
2389 }
2390}
2391
aaa1f954
EI
2392/* Update the Sixty-Four bit (SF) registersize. This logic is derived
2393 * from the ARMv8 specs for LDR (Shared decode for all encodings).
2394 */
2395static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc)
2396{
2397 int opc0 = extract32(opc, 0, 1);
2398 int regsize;
2399
2400 if (is_signed) {
2401 regsize = opc0 ? 32 : 64;
2402 } else {
2403 regsize = size == 3 ? 64 : 32;
2404 }
2405 return regsize == 64;
2406}
2407
4ce31af4 2408/* Load/store exclusive
fa2ef212
MM
2409 *
2410 * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
2411 * +-----+-------------+----+---+----+------+----+-------+------+------+
2412 * | sz | 0 0 1 0 0 0 | o2 | L | o1 | Rs | o0 | Rt2 | Rn | Rt |
2413 * +-----+-------------+----+---+----+------+----+-------+------+------+
2414 *
2415 * sz: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64 bit
2416 * L: 0 -> store, 1 -> load
2417 * o2: 0 -> exclusive, 1 -> not
2418 * o1: 0 -> single register, 1 -> register pair
2419 * o0: 1 -> load-acquire/store-release, 0 -> not
fa2ef212 2420 */
ad7ee8a2
CF
2421static void disas_ldst_excl(DisasContext *s, uint32_t insn)
2422{
fa2ef212
MM
2423 int rt = extract32(insn, 0, 5);
2424 int rn = extract32(insn, 5, 5);
2425 int rt2 = extract32(insn, 10, 5);
fa2ef212 2426 int rs = extract32(insn, 16, 5);
68412d2e
RH
2427 int is_lasr = extract32(insn, 15, 1);
2428 int o2_L_o1_o0 = extract32(insn, 21, 3) * 2 | is_lasr;
fa2ef212
MM
2429 int size = extract32(insn, 30, 2);
2430 TCGv_i64 tcg_addr;
2431
68412d2e
RH
2432 switch (o2_L_o1_o0) {
2433 case 0x0: /* STXR */
2434 case 0x1: /* STLXR */
2435 if (rn == 31) {
2436 gen_check_sp_alignment(s);
2437 }
2438 if (is_lasr) {
2439 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2440 }
2441 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2442 gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, false);
fa2ef212 2443 return;
fa2ef212 2444
68412d2e
RH
2445 case 0x4: /* LDXR */
2446 case 0x5: /* LDAXR */
2447 if (rn == 31) {
2448 gen_check_sp_alignment(s);
2449 }
2450 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2451 s->is_ldex = true;
2452 gen_load_exclusive(s, rt, rt2, tcg_addr, size, false);
2453 if (is_lasr) {
2454 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2455 }
2456 return;
fa2ef212 2457
2d7137c1
RH
2458 case 0x8: /* STLLR */
2459 if (!dc_isar_feature(aa64_lor, s)) {
2460 break;
2461 }
2462 /* StoreLORelease is the same as Store-Release for QEMU. */
2463 /* fall through */
68412d2e
RH
2464 case 0x9: /* STLR */
2465 /* Generate ISS for non-exclusive accesses including LASR. */
2466 if (rn == 31) {
2467 gen_check_sp_alignment(s);
2468 }
2469 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2470 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2471 do_gpr_st(s, cpu_reg(s, rt), tcg_addr, size, true, rt,
2472 disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
2473 return;
fa2ef212 2474
2d7137c1
RH
2475 case 0xc: /* LDLAR */
2476 if (!dc_isar_feature(aa64_lor, s)) {
2477 break;
2478 }
2479 /* LoadLOAcquire is the same as Load-Acquire for QEMU. */
2480 /* fall through */
68412d2e
RH
2481 case 0xd: /* LDAR */
2482 /* Generate ISS for non-exclusive accesses including LASR. */
2483 if (rn == 31) {
2484 gen_check_sp_alignment(s);
2485 }
2486 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2487 do_gpr_ld(s, cpu_reg(s, rt), tcg_addr, size, false, false, true, rt,
2488 disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
2489 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2490 return;
2491
2492 case 0x2: case 0x3: /* CASP / STXP */
2493 if (size & 2) { /* STXP / STLXP */
2494 if (rn == 31) {
2495 gen_check_sp_alignment(s);
ce1bd93f 2496 }
ce1bd93f
PK
2497 if (is_lasr) {
2498 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2499 }
68412d2e
RH
2500 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2501 gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, true);
2502 return;
fa2ef212 2503 }
44ac14b0
RH
2504 if (rt2 == 31
2505 && ((rt | rs) & 1) == 0
962fcbf2 2506 && dc_isar_feature(aa64_atomics, s)) {
44ac14b0
RH
2507 /* CASP / CASPL */
2508 gen_compare_and_swap_pair(s, rs, rt, rn, size | 2);
2509 return;
2510 }
68412d2e 2511 break;
aaa1f954 2512
44ac14b0 2513 case 0x6: case 0x7: /* CASPA / LDXP */
68412d2e
RH
2514 if (size & 2) { /* LDXP / LDAXP */
2515 if (rn == 31) {
2516 gen_check_sp_alignment(s);
ce1bd93f 2517 }
68412d2e
RH
2518 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2519 s->is_ldex = true;
2520 gen_load_exclusive(s, rt, rt2, tcg_addr, size, true);
ce1bd93f
PK
2521 if (is_lasr) {
2522 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2523 }
68412d2e 2524 return;
fa2ef212 2525 }
44ac14b0
RH
2526 if (rt2 == 31
2527 && ((rt | rs) & 1) == 0
962fcbf2 2528 && dc_isar_feature(aa64_atomics, s)) {
44ac14b0
RH
2529 /* CASPA / CASPAL */
2530 gen_compare_and_swap_pair(s, rs, rt, rn, size | 2);
2531 return;
fa2ef212 2532 }
68412d2e
RH
2533 break;
2534
2535 case 0xa: /* CAS */
2536 case 0xb: /* CASL */
2537 case 0xe: /* CASA */
2538 case 0xf: /* CASAL */
962fcbf2 2539 if (rt2 == 31 && dc_isar_feature(aa64_atomics, s)) {
44ac14b0
RH
2540 gen_compare_and_swap(s, rs, rt, rn, size);
2541 return;
2542 }
68412d2e 2543 break;
fa2ef212 2544 }
68412d2e 2545 unallocated_encoding(s);
ad7ee8a2
CF
2546}
2547
32b64e86 2548/*
4ce31af4 2549 * Load register (literal)
32b64e86
AG
2550 *
2551 * 31 30 29 27 26 25 24 23 5 4 0
2552 * +-----+-------+---+-----+-------------------+-------+
2553 * | opc | 0 1 1 | V | 0 0 | imm19 | Rt |
2554 * +-----+-------+---+-----+-------------------+-------+
2555 *
2556 * V: 1 -> vector (simd/fp)
2557 * opc (non-vector): 00 -> 32 bit, 01 -> 64 bit,
2558 * 10-> 32 bit signed, 11 -> prefetch
2559 * opc (vector): 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit (11 unallocated)
2560 */
ad7ee8a2
CF
2561static void disas_ld_lit(DisasContext *s, uint32_t insn)
2562{
32b64e86
AG
2563 int rt = extract32(insn, 0, 5);
2564 int64_t imm = sextract32(insn, 5, 19) << 2;
2565 bool is_vector = extract32(insn, 26, 1);
2566 int opc = extract32(insn, 30, 2);
2567 bool is_signed = false;
2568 int size = 2;
2569 TCGv_i64 tcg_rt, tcg_addr;
2570
2571 if (is_vector) {
2572 if (opc == 3) {
2573 unallocated_encoding(s);
2574 return;
2575 }
2576 size = 2 + opc;
8c6afa6a
PM
2577 if (!fp_access_check(s)) {
2578 return;
2579 }
32b64e86
AG
2580 } else {
2581 if (opc == 3) {
2582 /* PRFM (literal) : prefetch */
2583 return;
2584 }
2585 size = 2 + extract32(opc, 0, 1);
2586 is_signed = extract32(opc, 1, 1);
2587 }
2588
2589 tcg_rt = cpu_reg(s, rt);
2590
2591 tcg_addr = tcg_const_i64((s->pc - 4) + imm);
2592 if (is_vector) {
2593 do_fp_ld(s, rt, tcg_addr, size);
2594 } else {
aaa1f954 2595 /* Only unsigned 32bit loads target 32bit registers. */
173ff585 2596 bool iss_sf = opc != 0;
aaa1f954
EI
2597
2598 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false,
2599 true, rt, iss_sf, false);
32b64e86
AG
2600 }
2601 tcg_temp_free_i64(tcg_addr);
ad7ee8a2
CF
2602}
2603
4a08d475 2604/*
4ce31af4
PM
2605 * LDNP (Load Pair - non-temporal hint)
2606 * LDP (Load Pair - non vector)
2607 * LDPSW (Load Pair Signed Word - non vector)
2608 * STNP (Store Pair - non-temporal hint)
2609 * STP (Store Pair - non vector)
2610 * LDNP (Load Pair of SIMD&FP - non-temporal hint)
2611 * LDP (Load Pair of SIMD&FP)
2612 * STNP (Store Pair of SIMD&FP - non-temporal hint)
2613 * STP (Store Pair of SIMD&FP)
4a08d475
PM
2614 *
2615 * 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
2616 * +-----+-------+---+---+-------+---+-----------------------------+
2617 * | opc | 1 0 1 | V | 0 | index | L | imm7 | Rt2 | Rn | Rt |
2618 * +-----+-------+---+---+-------+---+-------+-------+------+------+
2619 *
2620 * opc: LDP/STP/LDNP/STNP 00 -> 32 bit, 10 -> 64 bit
2621 * LDPSW 01
2622 * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
2623 * V: 0 -> GPR, 1 -> Vector
2624 * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
2625 * 10 -> signed offset, 11 -> pre-index
2626 * L: 0 -> Store 1 -> Load
2627 *
2628 * Rt, Rt2 = GPR or SIMD registers to be stored
2629 * Rn = general purpose register containing address
2630 * imm7 = signed offset (multiple of 4 or 8 depending on size)
2631 */
ad7ee8a2
CF
2632static void disas_ldst_pair(DisasContext *s, uint32_t insn)
2633{
4a08d475
PM
2634 int rt = extract32(insn, 0, 5);
2635 int rn = extract32(insn, 5, 5);
2636 int rt2 = extract32(insn, 10, 5);
c2ebd862 2637 uint64_t offset = sextract64(insn, 15, 7);
4a08d475
PM
2638 int index = extract32(insn, 23, 2);
2639 bool is_vector = extract32(insn, 26, 1);
2640 bool is_load = extract32(insn, 22, 1);
2641 int opc = extract32(insn, 30, 2);
2642
2643 bool is_signed = false;
2644 bool postindex = false;
2645 bool wback = false;
2646
2647 TCGv_i64 tcg_addr; /* calculated address */
2648 int size;
2649
2650 if (opc == 3) {
2651 unallocated_encoding(s);
2652 return;
2653 }
2654
2655 if (is_vector) {
2656 size = 2 + opc;
2657 } else {
2658 size = 2 + extract32(opc, 1, 1);
2659 is_signed = extract32(opc, 0, 1);
2660 if (!is_load && is_signed) {
2661 unallocated_encoding(s);
2662 return;
2663 }
2664 }
2665
2666 switch (index) {
2667 case 1: /* post-index */
2668 postindex = true;
2669 wback = true;
2670 break;
2671 case 0:
2672 /* signed offset with "non-temporal" hint. Since we don't emulate
2673 * caches we don't care about hints to the cache system about
2674 * data access patterns, and handle this identically to plain
2675 * signed offset.
2676 */
2677 if (is_signed) {
2678 /* There is no non-temporal-hint version of LDPSW */
2679 unallocated_encoding(s);
2680 return;
2681 }
2682 postindex = false;
2683 break;
2684 case 2: /* signed offset, rn not updated */
2685 postindex = false;
2686 break;
2687 case 3: /* pre-index */
2688 postindex = false;
2689 wback = true;
2690 break;
2691 }
2692
8c6afa6a
PM
2693 if (is_vector && !fp_access_check(s)) {
2694 return;
2695 }
2696
4a08d475
PM
2697 offset <<= size;
2698
2699 if (rn == 31) {
2700 gen_check_sp_alignment(s);
2701 }
2702
2703 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2704
2705 if (!postindex) {
2706 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
2707 }
2708
2709 if (is_vector) {
2710 if (is_load) {
2711 do_fp_ld(s, rt, tcg_addr, size);
2712 } else {
2713 do_fp_st(s, rt, tcg_addr, size);
2714 }
3e4d91b9 2715 tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
4a08d475
PM
2716 if (is_load) {
2717 do_fp_ld(s, rt2, tcg_addr, size);
2718 } else {
2719 do_fp_st(s, rt2, tcg_addr, size);
2720 }
2721 } else {
3e4d91b9 2722 TCGv_i64 tcg_rt = cpu_reg(s, rt);
4a08d475 2723 TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
3e4d91b9 2724
4a08d475 2725 if (is_load) {
3e4d91b9
RH
2726 TCGv_i64 tmp = tcg_temp_new_i64();
2727
2728 /* Do not modify tcg_rt before recognizing any exception
2729 * from the second load.
2730 */
2731 do_gpr_ld(s, tmp, tcg_addr, size, is_signed, false,
2732 false, 0, false, false);
2733 tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
aaa1f954
EI
2734 do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false,
2735 false, 0, false, false);
3e4d91b9
RH
2736
2737 tcg_gen_mov_i64(tcg_rt, tmp);
2738 tcg_temp_free_i64(tmp);
4a08d475 2739 } else {
3e4d91b9
RH
2740 do_gpr_st(s, tcg_rt, tcg_addr, size,
2741 false, 0, false, false);
2742 tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
aaa1f954
EI
2743 do_gpr_st(s, tcg_rt2, tcg_addr, size,
2744 false, 0, false, false);
4a08d475
PM
2745 }
2746 }
2747
2748 if (wback) {
2749 if (postindex) {
2750 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
2751 } else {
2752 tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
2753 }
2754 tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
2755 }
ad7ee8a2
CF
2756}
2757
a5e94a9d 2758/*
4ce31af4
PM
2759 * Load/store (immediate post-indexed)
2760 * Load/store (immediate pre-indexed)
2761 * Load/store (unscaled immediate)
a5e94a9d
AB
2762 *
2763 * 31 30 29 27 26 25 24 23 22 21 20 12 11 10 9 5 4 0
2764 * +----+-------+---+-----+-----+---+--------+-----+------+------+
2765 * |size| 1 1 1 | V | 0 0 | opc | 0 | imm9 | idx | Rn | Rt |
2766 * +----+-------+---+-----+-----+---+--------+-----+------+------+
2767 *
2768 * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
60510aed 2769 10 -> unprivileged
a5e94a9d
AB
2770 * V = 0 -> non-vector
2771 * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
2772 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
2773 */
cd694521
EI
2774static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
2775 int opc,
2776 int size,
2777 int rt,
2778 bool is_vector)
a5e94a9d 2779{
a5e94a9d
AB
2780 int rn = extract32(insn, 5, 5);
2781 int imm9 = sextract32(insn, 12, 9);
a5e94a9d
AB
2782 int idx = extract32(insn, 10, 2);
2783 bool is_signed = false;
2784 bool is_store = false;
2785 bool is_extended = false;
60510aed 2786 bool is_unpriv = (idx == 2);
aaa1f954 2787 bool iss_valid = !is_vector;
a5e94a9d
AB
2788 bool post_index;
2789 bool writeback;
2790
2791 TCGv_i64 tcg_addr;
2792
2793 if (is_vector) {
2794 size |= (opc & 2) << 1;
60510aed 2795 if (size > 4 || is_unpriv) {
a5e94a9d
AB
2796 unallocated_encoding(s);
2797 return;
2798 }
2799 is_store = ((opc & 1) == 0);
8c6afa6a
PM
2800 if (!fp_access_check(s)) {
2801 return;
2802 }
a5e94a9d
AB
2803 } else {
2804 if (size == 3 && opc == 2) {
2805 /* PRFM - prefetch */
a80c4256 2806 if (idx != 0) {
60510aed
PM
2807 unallocated_encoding(s);
2808 return;
2809 }
a5e94a9d
AB
2810 return;
2811 }
2812 if (opc == 3 && size > 1) {
2813 unallocated_encoding(s);
2814 return;
2815 }
2816 is_store = (opc == 0);
026a19c3
EI
2817 is_signed = extract32(opc, 1, 1);
2818 is_extended = (size < 3) && extract32(opc, 0, 1);
a5e94a9d
AB
2819 }
2820
2821 switch (idx) {
2822 case 0:
60510aed 2823 case 2:
a5e94a9d
AB
2824 post_index = false;
2825 writeback = false;
2826 break;
2827 case 1:
2828 post_index = true;
2829 writeback = true;
2830 break;
2831 case 3:
2832 post_index = false;
2833 writeback = true;
2834 break;
5ca66278
EC
2835 default:
2836 g_assert_not_reached();
a5e94a9d
AB
2837 }
2838
2839 if (rn == 31) {
2840 gen_check_sp_alignment(s);
2841 }
2842 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2843
2844 if (!post_index) {
2845 tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
2846 }
2847
2848 if (is_vector) {
2849 if (is_store) {
2850 do_fp_st(s, rt, tcg_addr, size);
2851 } else {
2852 do_fp_ld(s, rt, tcg_addr, size);
2853 }
2854 } else {
2855 TCGv_i64 tcg_rt = cpu_reg(s, rt);
579d21cc 2856 int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
aaa1f954 2857 bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
60510aed 2858
a5e94a9d 2859 if (is_store) {
aaa1f954
EI
2860 do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx,
2861 iss_valid, rt, iss_sf, false);
a5e94a9d 2862 } else {
60510aed 2863 do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size,
aaa1f954
EI
2864 is_signed, is_extended, memidx,
2865 iss_valid, rt, iss_sf, false);
a5e94a9d
AB
2866 }
2867 }
2868
2869 if (writeback) {
2870 TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
2871 if (post_index) {
2872 tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
2873 }
2874 tcg_gen_mov_i64(tcg_rn, tcg_addr);
2875 }
2876}
2877
229b7a05 2878/*
4ce31af4 2879 * Load/store (register offset)
229b7a05
AB
2880 *
2881 * 31 30 29 27 26 25 24 23 22 21 20 16 15 13 12 11 10 9 5 4 0
2882 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
2883 * |size| 1 1 1 | V | 0 0 | opc | 1 | Rm | opt | S| 1 0 | Rn | Rt |
2884 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
2885 *
2886 * For non-vector:
2887 * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
2888 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
2889 * For vector:
2890 * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
2891 * opc<0>: 0 -> store, 1 -> load
2892 * V: 1 -> vector/simd
2893 * opt: extend encoding (see DecodeRegExtend)
2894 * S: if S=1 then scale (essentially index by sizeof(size))
2895 * Rt: register to transfer into/out of
2896 * Rn: address register or SP for base
2897 * Rm: offset register or ZR for offset
2898 */
cd694521
EI
2899static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
2900 int opc,
2901 int size,
2902 int rt,
2903 bool is_vector)
229b7a05 2904{
229b7a05
AB
2905 int rn = extract32(insn, 5, 5);
2906 int shift = extract32(insn, 12, 1);
2907 int rm = extract32(insn, 16, 5);
229b7a05 2908 int opt = extract32(insn, 13, 3);
229b7a05
AB
2909 bool is_signed = false;
2910 bool is_store = false;
2911 bool is_extended = false;
229b7a05
AB
2912
2913 TCGv_i64 tcg_rm;
2914 TCGv_i64 tcg_addr;
2915
2916 if (extract32(opt, 1, 1) == 0) {
2917 unallocated_encoding(s);
2918 return;
2919 }
2920
2921 if (is_vector) {
2922 size |= (opc & 2) << 1;
2923 if (size > 4) {
2924 unallocated_encoding(s);
2925 return;
2926 }
2927 is_store = !extract32(opc, 0, 1);
8c6afa6a
PM
2928 if (!fp_access_check(s)) {
2929 return;
2930 }
229b7a05
AB
2931 } else {
2932 if (size == 3 && opc == 2) {
2933 /* PRFM - prefetch */
2934 return;
2935 }
2936 if (opc == 3 && size > 1) {
2937 unallocated_encoding(s);
2938 return;
2939 }
2940 is_store = (opc == 0);
2941 is_signed = extract32(opc, 1, 1);
2942 is_extended = (size < 3) && extract32(opc, 0, 1);
2943 }
2944
2945 if (rn == 31) {
2946 gen_check_sp_alignment(s);
2947 }
2948 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2949
2950 tcg_rm = read_cpu_reg(s, rm, 1);
2951 ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
2952
2953 tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
2954
2955 if (is_vector) {
2956 if (is_store) {
2957 do_fp_st(s, rt, tcg_addr, size);
2958 } else {
2959 do_fp_ld(s, rt, tcg_addr, size);
2960 }
2961 } else {
2962 TCGv_i64 tcg_rt = cpu_reg(s, rt);
aaa1f954 2963 bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
229b7a05 2964 if (is_store) {
aaa1f954
EI
2965 do_gpr_st(s, tcg_rt, tcg_addr, size,
2966 true, rt, iss_sf, false);
229b7a05 2967 } else {
aaa1f954
EI
2968 do_gpr_ld(s, tcg_rt, tcg_addr, size,
2969 is_signed, is_extended,
2970 true, rt, iss_sf, false);
229b7a05
AB
2971 }
2972 }
2973}
2974
d5612f10 2975/*
4ce31af4 2976 * Load/store (unsigned immediate)
d5612f10
AB
2977 *
2978 * 31 30 29 27 26 25 24 23 22 21 10 9 5
2979 * +----+-------+---+-----+-----+------------+-------+------+
2980 * |size| 1 1 1 | V | 0 1 | opc | imm12 | Rn | Rt |
2981 * +----+-------+---+-----+-----+------------+-------+------+
2982 *
2983 * For non-vector:
2984 * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
2985 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
2986 * For vector:
2987 * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
2988 * opc<0>: 0 -> store, 1 -> load
2989 * Rn: base address register (inc SP)
2990 * Rt: target register
2991 */
cd694521
EI
2992static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
2993 int opc,
2994 int size,
2995 int rt,
2996 bool is_vector)
d5612f10 2997{
d5612f10
AB
2998 int rn = extract32(insn, 5, 5);
2999 unsigned int imm12 = extract32(insn, 10, 12);
d5612f10
AB
3000 unsigned int offset;
3001
3002 TCGv_i64 tcg_addr;
3003
3004 bool is_store;
3005 bool is_signed = false;
3006 bool is_extended = false;
3007
3008 if (is_vector) {
3009 size |= (opc & 2) << 1;
3010 if (size > 4) {
3011 unallocated_encoding(s);
3012 return;
3013 }
3014 is_store = !extract32(opc, 0, 1);
8c6afa6a
PM
3015 if (!fp_access_check(s)) {
3016 return;
3017 }
d5612f10
AB
3018 } else {
3019 if (size == 3 && opc == 2) {
3020 /* PRFM - prefetch */
3021 return;
3022 }
3023 if (opc == 3 && size > 1) {
3024 unallocated_encoding(s);
3025 return;
3026 }
3027 is_store = (opc == 0);
3028 is_signed = extract32(opc, 1, 1);
3029 is_extended = (size < 3) && extract32(opc, 0, 1);
3030 }
3031
3032 if (rn == 31) {
3033 gen_check_sp_alignment(s);
3034 }
3035 tcg_addr = read_cpu_reg_sp(s, rn, 1);
3036 offset = imm12 << size;
3037 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
3038
3039 if (is_vector) {
3040 if (is_store) {
3041 do_fp_st(s, rt, tcg_addr, size);
3042 } else {
3043 do_fp_ld(s, rt, tcg_addr, size);
3044 }
3045 } else {
3046 TCGv_i64 tcg_rt = cpu_reg(s, rt);
aaa1f954 3047 bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
d5612f10 3048 if (is_store) {
aaa1f954
EI
3049 do_gpr_st(s, tcg_rt, tcg_addr, size,
3050 true, rt, iss_sf, false);
d5612f10 3051 } else {
aaa1f954
EI
3052 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended,
3053 true, rt, iss_sf, false);
d5612f10
AB
3054 }
3055 }
3056}
3057
68412d2e
RH
3058/* Atomic memory operations
3059 *
3060 * 31 30 27 26 24 22 21 16 15 12 10 5 0
3061 * +------+-------+---+-----+-----+---+----+----+-----+-----+----+-----+
3062 * | size | 1 1 1 | V | 0 0 | A R | 1 | Rs | o3 | opc | 0 0 | Rn | Rt |
3063 * +------+-------+---+-----+-----+--------+----+-----+-----+----+-----+
3064 *
3065 * Rt: the result register
3066 * Rn: base address or SP
3067 * Rs: the source register for the operation
3068 * V: vector flag (always 0 as of v8.3)
3069 * A: acquire flag
3070 * R: release flag
3071 */
3072static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
3073 int size, int rt, bool is_vector)
3074{
3075 int rs = extract32(insn, 16, 5);
3076 int rn = extract32(insn, 5, 5);
3077 int o3_opc = extract32(insn, 12, 4);
74608ea4
RH
3078 TCGv_i64 tcg_rn, tcg_rs;
3079 AtomicThreeOpFn *fn;
68412d2e 3080
962fcbf2 3081 if (is_vector || !dc_isar_feature(aa64_atomics, s)) {
68412d2e
RH
3082 unallocated_encoding(s);
3083 return;
3084 }
3085 switch (o3_opc) {
3086 case 000: /* LDADD */
74608ea4
RH
3087 fn = tcg_gen_atomic_fetch_add_i64;
3088 break;
68412d2e 3089 case 001: /* LDCLR */
74608ea4
RH
3090 fn = tcg_gen_atomic_fetch_and_i64;
3091 break;
68412d2e 3092 case 002: /* LDEOR */
74608ea4
RH
3093 fn = tcg_gen_atomic_fetch_xor_i64;
3094 break;
68412d2e 3095 case 003: /* LDSET */
74608ea4
RH
3096 fn = tcg_gen_atomic_fetch_or_i64;
3097 break;
68412d2e 3098 case 004: /* LDSMAX */
74608ea4
RH
3099 fn = tcg_gen_atomic_fetch_smax_i64;
3100 break;
68412d2e 3101 case 005: /* LDSMIN */
74608ea4
RH
3102 fn = tcg_gen_atomic_fetch_smin_i64;
3103 break;
68412d2e 3104 case 006: /* LDUMAX */
74608ea4
RH
3105 fn = tcg_gen_atomic_fetch_umax_i64;
3106 break;
68412d2e 3107 case 007: /* LDUMIN */
74608ea4
RH
3108 fn = tcg_gen_atomic_fetch_umin_i64;
3109 break;
68412d2e 3110 case 010: /* SWP */
74608ea4
RH
3111 fn = tcg_gen_atomic_xchg_i64;
3112 break;
68412d2e
RH
3113 default:
3114 unallocated_encoding(s);
3115 return;
3116 }
68412d2e 3117
74608ea4
RH
3118 if (rn == 31) {
3119 gen_check_sp_alignment(s);
3120 }
3121 tcg_rn = cpu_reg_sp(s, rn);
3122 tcg_rs = read_cpu_reg(s, rs, true);
3123
3124 if (o3_opc == 1) { /* LDCLR */
3125 tcg_gen_not_i64(tcg_rs, tcg_rs);
3126 }
3127
3128 /* The tcg atomic primitives are all full barriers. Therefore we
3129 * can ignore the Acquire and Release bits of this instruction.
3130 */
3131 fn(cpu_reg(s, rt), tcg_rn, tcg_rs, get_mem_index(s),
3132 s->be_data | size | MO_ALIGN);
68412d2e
RH
3133}
3134
bd889f48
RH
3135/*
3136 * PAC memory operations
3137 *
3138 * 31 30 27 26 24 22 21 12 11 10 5 0
3139 * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
3140 * | size | 1 1 1 | V | 0 0 | M S | 1 | imm9 | W | 1 | Rn | Rt |
3141 * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
3142 *
3143 * Rt: the result register
3144 * Rn: base address or SP
3145 * V: vector flag (always 0 as of v8.3)
3146 * M: clear for key DA, set for key DB
3147 * W: pre-indexing flag
3148 * S: sign for imm9.
3149 */
3150static void disas_ldst_pac(DisasContext *s, uint32_t insn,
3151 int size, int rt, bool is_vector)
3152{
3153 int rn = extract32(insn, 5, 5);
3154 bool is_wback = extract32(insn, 11, 1);
3155 bool use_key_a = !extract32(insn, 23, 1);
3156 int offset;
3157 TCGv_i64 tcg_addr, tcg_rt;
3158
3159 if (size != 3 || is_vector || !dc_isar_feature(aa64_pauth, s)) {
3160 unallocated_encoding(s);
3161 return;
3162 }
3163
3164 if (rn == 31) {
3165 gen_check_sp_alignment(s);
3166 }
3167 tcg_addr = read_cpu_reg_sp(s, rn, 1);
3168
3169 if (s->pauth_active) {
3170 if (use_key_a) {
3171 gen_helper_autda(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
3172 } else {
3173 gen_helper_autdb(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
3174 }
3175 }
3176
3177 /* Form the 10-bit signed, scaled offset. */
3178 offset = (extract32(insn, 22, 1) << 9) | extract32(insn, 12, 9);
3179 offset = sextract32(offset << size, 0, 10 + size);
3180 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
3181
3182 tcg_rt = cpu_reg(s, rt);
3183
3184 do_gpr_ld(s, tcg_rt, tcg_addr, size, /* is_signed */ false,
3185 /* extend */ false, /* iss_valid */ !is_wback,
3186 /* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false);
3187
3188 if (is_wback) {
3189 tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
3190 }
3191}
3192
ad7ee8a2
CF
3193/* Load/store register (all forms) */
3194static void disas_ldst_reg(DisasContext *s, uint32_t insn)
3195{
cd694521
EI
3196 int rt = extract32(insn, 0, 5);
3197 int opc = extract32(insn, 22, 2);
3198 bool is_vector = extract32(insn, 26, 1);
3199 int size = extract32(insn, 30, 2);
3200
d5612f10
AB
3201 switch (extract32(insn, 24, 2)) {
3202 case 0:
68412d2e 3203 if (extract32(insn, 21, 1) == 0) {
60510aed
PM
3204 /* Load/store register (unscaled immediate)
3205 * Load/store immediate pre/post-indexed
3206 * Load/store register unprivileged
3207 */
cd694521 3208 disas_ldst_reg_imm9(s, insn, opc, size, rt, is_vector);
68412d2e
RH
3209 return;
3210 }
3211 switch (extract32(insn, 10, 2)) {
3212 case 0:
3213 disas_ldst_atomic(s, insn, size, rt, is_vector);
3214 return;
3215 case 2:
3216 disas_ldst_reg_roffset(s, insn, opc, size, rt, is_vector);
3217 return;
bd889f48
RH
3218 default:
3219 disas_ldst_pac(s, insn, size, rt, is_vector);
3220 return;
229b7a05 3221 }
d5612f10
AB
3222 break;
3223 case 1:
cd694521 3224 disas_ldst_reg_unsigned_imm(s, insn, opc, size, rt, is_vector);
68412d2e 3225 return;
d5612f10 3226 }
68412d2e 3227 unallocated_encoding(s);
ad7ee8a2
CF
3228}
3229
4ce31af4 3230/* AdvSIMD load/store multiple structures
72430bf5
AB
3231 *
3232 * 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
3233 * +---+---+---------------+---+-------------+--------+------+------+------+
3234 * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt |
3235 * +---+---+---------------+---+-------------+--------+------+------+------+
3236 *
4ce31af4 3237 * AdvSIMD load/store multiple structures (post-indexed)
72430bf5
AB
3238 *
3239 * 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0
3240 * +---+---+---------------+---+---+---------+--------+------+------+------+
3241 * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 | Rm | opcode | size | Rn | Rt |
3242 * +---+---+---------------+---+---+---------+--------+------+------+------+
3243 *
3244 * Rt: first (or only) SIMD&FP register to be transferred
3245 * Rn: base address or SP
3246 * Rm (post-index only): post-index register (when !31) or size dependent #imm
3247 */
ad7ee8a2
CF
3248static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
3249{
72430bf5
AB
3250 int rt = extract32(insn, 0, 5);
3251 int rn = extract32(insn, 5, 5);
e1f22081 3252 int rm = extract32(insn, 16, 5);
72430bf5
AB
3253 int size = extract32(insn, 10, 2);
3254 int opcode = extract32(insn, 12, 4);
3255 bool is_store = !extract32(insn, 22, 1);
3256 bool is_postidx = extract32(insn, 23, 1);
3257 bool is_q = extract32(insn, 30, 1);
a7d8143a 3258 TCGv_i64 tcg_addr, tcg_rn, tcg_ebytes;
87f9a7f0 3259 TCGMemOp endian = s->be_data;
72430bf5 3260
87f9a7f0
RH
3261 int ebytes; /* bytes per element */
3262 int elements; /* elements per vector */
72430bf5
AB
3263 int rpt; /* num iterations */
3264 int selem; /* structure elements */
3265 int r;
3266
3267 if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
3268 unallocated_encoding(s);
3269 return;
3270 }
3271
e1f22081
PM
3272 if (!is_postidx && rm != 0) {
3273 unallocated_encoding(s);
3274 return;
3275 }
3276
72430bf5
AB
3277 /* From the shared decode logic */
3278 switch (opcode) {
3279 case 0x0:
3280 rpt = 1;
3281 selem = 4;
3282 break;
3283 case 0x2:
3284 rpt = 4;
3285 selem = 1;
3286 break;
3287 case 0x4:
3288 rpt = 1;
3289 selem = 3;
3290 break;
3291 case 0x6:
3292 rpt = 3;
3293 selem = 1;
3294 break;
3295 case 0x7:
3296 rpt = 1;
3297 selem = 1;
3298 break;
3299 case 0x8:
3300 rpt = 1;
3301 selem = 2;
3302 break;
3303 case 0xa:
3304 rpt = 2;
3305 selem = 1;
3306 break;
3307 default:
3308 unallocated_encoding(s);
3309 return;
3310 }
3311
3312 if (size == 3 && !is_q && selem != 1) {
3313 /* reserved */
3314 unallocated_encoding(s);
3315 return;
3316 }
3317
8c6afa6a
PM
3318 if (!fp_access_check(s)) {
3319 return;
3320 }
3321
72430bf5
AB
3322 if (rn == 31) {
3323 gen_check_sp_alignment(s);
3324 }
3325
87f9a7f0
RH
3326 /* For our purposes, bytes are always little-endian. */
3327 if (size == 0) {
3328 endian = MO_LE;
3329 }
3330
3331 /* Consecutive little-endian elements from a single register
3332 * can be promoted to a larger little-endian operation.
3333 */
3334 if (selem == 1 && endian == MO_LE) {
3335 size = 3;
3336 }
3337 ebytes = 1 << size;
3338 elements = (is_q ? 16 : 8) / ebytes;
3339
72430bf5
AB
3340 tcg_rn = cpu_reg_sp(s, rn);
3341 tcg_addr = tcg_temp_new_i64();
3342 tcg_gen_mov_i64(tcg_addr, tcg_rn);
a7d8143a 3343 tcg_ebytes = tcg_const_i64(ebytes);
72430bf5
AB
3344
3345 for (r = 0; r < rpt; r++) {
3346 int e;
3347 for (e = 0; e < elements; e++) {
72430bf5
AB
3348 int xs;
3349 for (xs = 0; xs < selem; xs++) {
87f9a7f0 3350 int tt = (rt + r + xs) % 32;
72430bf5 3351 if (is_store) {
87f9a7f0 3352 do_vec_st(s, tt, e, tcg_addr, size, endian);
72430bf5 3353 } else {
87f9a7f0 3354 do_vec_ld(s, tt, e, tcg_addr, size, endian);
72430bf5 3355 }
a7d8143a 3356 tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_ebytes);
72430bf5
AB
3357 }
3358 }
3359 }
3360
87f9a7f0
RH
3361 if (!is_store) {
3362 /* For non-quad operations, setting a slice of the low
3363 * 64 bits of the register clears the high 64 bits (in
3364 * the ARM ARM pseudocode this is implicit in the fact
3365 * that 'rval' is a 64 bit wide variable).
3366 * For quad operations, we might still need to zero the
3367 * high bits of SVE.
3368 */
3369 for (r = 0; r < rpt * selem; r++) {
3370 int tt = (rt + r) % 32;
3371 clear_vec_high(s, is_q, tt);
3372 }
3373 }
3374
72430bf5 3375 if (is_postidx) {
72430bf5
AB
3376 if (rm == 31) {
3377 tcg_gen_mov_i64(tcg_rn, tcg_addr);
3378 } else {
3379 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
3380 }
3381 }
a7d8143a 3382 tcg_temp_free_i64(tcg_ebytes);
72430bf5 3383 tcg_temp_free_i64(tcg_addr);
ad7ee8a2
CF
3384}
3385
4ce31af4 3386/* AdvSIMD load/store single structure
df54e47d
PM
3387 *
3388 * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
3389 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
3390 * | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size | Rn | Rt |
3391 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
3392 *
4ce31af4 3393 * AdvSIMD load/store single structure (post-indexed)
df54e47d
PM
3394 *
3395 * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
3396 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
3397 * | 0 | Q | 0 0 1 1 0 1 1 | L R | Rm | opc | S | size | Rn | Rt |
3398 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
3399 *
3400 * Rt: first (or only) SIMD&FP register to be transferred
3401 * Rn: base address or SP
3402 * Rm (post-index only): post-index register (when !31) or size dependent #imm
3403 * index = encoded in Q:S:size dependent on size
3404 *
3405 * lane_size = encoded in R, opc
3406 * transfer width = encoded in opc, S, size
3407 */
ad7ee8a2
CF
3408static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
3409{
df54e47d
PM
3410 int rt = extract32(insn, 0, 5);
3411 int rn = extract32(insn, 5, 5);
9c72b68a 3412 int rm = extract32(insn, 16, 5);
df54e47d
PM
3413 int size = extract32(insn, 10, 2);
3414 int S = extract32(insn, 12, 1);
3415 int opc = extract32(insn, 13, 3);
3416 int R = extract32(insn, 21, 1);
3417 int is_load = extract32(insn, 22, 1);
3418 int is_postidx = extract32(insn, 23, 1);
3419 int is_q = extract32(insn, 30, 1);
3420
3421 int scale = extract32(opc, 1, 2);
3422 int selem = (extract32(opc, 0, 1) << 1 | R) + 1;
3423 bool replicate = false;
3424 int index = is_q << 3 | S << 2 | size;
3425 int ebytes, xs;
a7d8143a 3426 TCGv_i64 tcg_addr, tcg_rn, tcg_ebytes;
df54e47d 3427
9c72b68a
PM
3428 if (extract32(insn, 31, 1)) {
3429 unallocated_encoding(s);
3430 return;
3431 }
3432 if (!is_postidx && rm != 0) {
3433 unallocated_encoding(s);
3434 return;
3435 }
3436
df54e47d
PM
3437 switch (scale) {
3438 case 3:
3439 if (!is_load || S) {
3440 unallocated_encoding(s);
3441 return;
3442 }
3443 scale = size;
3444 replicate = true;
3445 break;
3446 case 0:
3447 break;
3448 case 1:
3449 if (extract32(size, 0, 1)) {
3450 unallocated_encoding(s);
3451 return;
3452 }
3453 index >>= 1;
3454 break;
3455 case 2:
3456 if (extract32(size, 1, 1)) {
3457 unallocated_encoding(s);
3458 return;
3459 }
3460 if (!extract32(size, 0, 1)) {
3461 index >>= 2;
3462 } else {
3463 if (S) {
3464 unallocated_encoding(s);
3465 return;
3466 }
3467 index >>= 3;
3468 scale = 3;
3469 }
3470 break;
3471 default:
3472 g_assert_not_reached();
3473 }
3474
8c6afa6a
PM
3475 if (!fp_access_check(s)) {
3476 return;
3477 }
3478
df54e47d
PM
3479 ebytes = 1 << scale;
3480
3481 if (rn == 31) {
3482 gen_check_sp_alignment(s);
3483 }
3484
3485 tcg_rn = cpu_reg_sp(s, rn);
3486 tcg_addr = tcg_temp_new_i64();
3487 tcg_gen_mov_i64(tcg_addr, tcg_rn);
a7d8143a 3488 tcg_ebytes = tcg_const_i64(ebytes);
df54e47d
PM
3489
3490 for (xs = 0; xs < selem; xs++) {
3491 if (replicate) {
3492 /* Load and replicate to all elements */
df54e47d
PM
3493 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3494
3495 tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr,
aa6489da 3496 get_mem_index(s), s->be_data + scale);
10e0b33c
RH
3497 tcg_gen_gvec_dup_i64(scale, vec_full_reg_offset(s, rt),
3498 (is_q + 1) * 8, vec_full_reg_size(s),
3499 tcg_tmp);
df54e47d
PM
3500 tcg_temp_free_i64(tcg_tmp);
3501 } else {
3502 /* Load/store one element per register */
3503 if (is_load) {
87f9a7f0 3504 do_vec_ld(s, rt, index, tcg_addr, scale, s->be_data);
df54e47d 3505 } else {
87f9a7f0 3506 do_vec_st(s, rt, index, tcg_addr, scale, s->be_data);
df54e47d
PM
3507 }
3508 }
a7d8143a 3509 tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_ebytes);
df54e47d
PM
3510 rt = (rt + 1) % 32;
3511 }
3512
3513 if (is_postidx) {
df54e47d
PM
3514 if (rm == 31) {
3515 tcg_gen_mov_i64(tcg_rn, tcg_addr);
3516 } else {
3517 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
3518 }
3519 }
a7d8143a 3520 tcg_temp_free_i64(tcg_ebytes);
df54e47d 3521 tcg_temp_free_i64(tcg_addr);
ad7ee8a2
CF
3522}
3523
4ce31af4 3524/* Loads and stores */
ad7ee8a2
CF
3525static void disas_ldst(DisasContext *s, uint32_t insn)
3526{
3527 switch (extract32(insn, 24, 6)) {
3528 case 0x08: /* Load/store exclusive */
3529 disas_ldst_excl(s, insn);
3530 break;
3531 case 0x18: case 0x1c: /* Load register (literal) */
3532 disas_ld_lit(s, insn);
3533 break;
3534 case 0x28: case 0x29:
3535 case 0x2c: case 0x2d: /* Load/store pair (all forms) */
3536 disas_ldst_pair(s, insn);
3537 break;
3538 case 0x38: case 0x39:
3539 case 0x3c: case 0x3d: /* Load/store register (all forms) */
3540 disas_ldst_reg(s, insn);
3541 break;
3542 case 0x0c: /* AdvSIMD load/store multiple structures */
3543 disas_ldst_multiple_struct(s, insn);
3544 break;
3545 case 0x0d: /* AdvSIMD load/store single structure */
3546 disas_ldst_single_struct(s, insn);
3547 break;
3548 default:
3549 unallocated_encoding(s);
3550 break;
3551 }
3552}
3553
4ce31af4 3554/* PC-rel. addressing
15bfe8b6
AG
3555 * 31 30 29 28 24 23 5 4 0
3556 * +----+-------+-----------+-------------------+------+
3557 * | op | immlo | 1 0 0 0 0 | immhi | Rd |
3558 * +----+-------+-----------+-------------------+------+
3559 */
ad7ee8a2
CF
3560static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
3561{
15bfe8b6
AG
3562 unsigned int page, rd;
3563 uint64_t base;
037e1d00 3564 uint64_t offset;
15bfe8b6
AG
3565
3566 page = extract32(insn, 31, 1);
3567 /* SignExtend(immhi:immlo) -> offset */
037e1d00
PM
3568 offset = sextract64(insn, 5, 19);
3569 offset = offset << 2 | extract32(insn, 29, 2);
15bfe8b6
AG
3570 rd = extract32(insn, 0, 5);
3571 base = s->pc - 4;
3572
3573 if (page) {
3574 /* ADRP (page based) */
3575 base &= ~0xfff;
3576 offset <<= 12;
3577 }
3578
3579 tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
ad7ee8a2
CF
3580}
3581
b0ff21b4 3582/*
4ce31af4 3583 * Add/subtract (immediate)
b0ff21b4
AB
3584 *
3585 * 31 30 29 28 24 23 22 21 10 9 5 4 0
3586 * +--+--+--+-----------+-----+-------------+-----+-----+
3587 * |sf|op| S| 1 0 0 0 1 |shift| imm12 | Rn | Rd |
3588 * +--+--+--+-----------+-----+-------------+-----+-----+
3589 *
3590 * sf: 0 -> 32bit, 1 -> 64bit
3591 * op: 0 -> add , 1 -> sub
3592 * S: 1 -> set flags
3593 * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12
3594 */
ad7ee8a2
CF
3595static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
3596{
b0ff21b4
AB
3597 int rd = extract32(insn, 0, 5);
3598 int rn = extract32(insn, 5, 5);
3599 uint64_t imm = extract32(insn, 10, 12);
3600 int shift = extract32(insn, 22, 2);
3601 bool setflags = extract32(insn, 29, 1);
3602 bool sub_op = extract32(insn, 30, 1);
3603 bool is_64bit = extract32(insn, 31, 1);
3604
3605 TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
3606 TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
3607 TCGv_i64 tcg_result;
3608
3609 switch (shift) {
3610 case 0x0:
3611 break;
3612 case 0x1:
3613 imm <<= 12;
3614 break;
3615 default:
3616 unallocated_encoding(s);
3617 return;
3618 }
3619
3620 tcg_result = tcg_temp_new_i64();
3621 if (!setflags) {
3622 if (sub_op) {
3623 tcg_gen_subi_i64(tcg_result, tcg_rn, imm);
3624 } else {
3625 tcg_gen_addi_i64(tcg_result, tcg_rn, imm);
3626 }
3627 } else {
3628 TCGv_i64 tcg_imm = tcg_const_i64(imm);
3629 if (sub_op) {
3630 gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
3631 } else {
3632 gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
3633 }
3634 tcg_temp_free_i64(tcg_imm);
3635 }
3636
3637 if (is_64bit) {
3638 tcg_gen_mov_i64(tcg_rd, tcg_result);
3639 } else {
3640 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
3641 }
3642
3643 tcg_temp_free_i64(tcg_result);
ad7ee8a2
CF
3644}
3645
71b46089
AG
3646/* The input should be a value in the bottom e bits (with higher
3647 * bits zero); returns that value replicated into every element
3648 * of size e in a 64 bit integer.
3649 */
3650static uint64_t bitfield_replicate(uint64_t mask, unsigned int e)
3651{
3652 assert(e != 0);
3653 while (e < 64) {
3654 mask |= mask << e;
3655 e *= 2;
3656 }
3657 return mask;
3658}
3659
3660/* Return a value with the bottom len bits set (where 0 < len <= 64) */
3661static inline uint64_t bitmask64(unsigned int length)
3662{
3663 assert(length > 0 && length <= 64);
3664 return ~0ULL >> (64 - length);
3665}
3666
3667/* Simplified variant of pseudocode DecodeBitMasks() for the case where we
3668 * only require the wmask. Returns false if the imms/immr/immn are a reserved
3669 * value (ie should cause a guest UNDEF exception), and true if they are
3670 * valid, in which case the decoded bit pattern is written to result.
3671 */
8c71baed
RH
3672bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
3673 unsigned int imms, unsigned int immr)
71b46089
AG
3674{
3675 uint64_t mask;
3676 unsigned e, levels, s, r;
3677 int len;
3678
3679 assert(immn < 2 && imms < 64 && immr < 64);
3680
3681 /* The bit patterns we create here are 64 bit patterns which
3682 * are vectors of identical elements of size e = 2, 4, 8, 16, 32 or
3683 * 64 bits each. Each element contains the same value: a run
3684 * of between 1 and e-1 non-zero bits, rotated within the
3685 * element by between 0 and e-1 bits.
3686 *
3687 * The element size and run length are encoded into immn (1 bit)
3688 * and imms (6 bits) as follows:
3689 * 64 bit elements: immn = 1, imms = <length of run - 1>
3690 * 32 bit elements: immn = 0, imms = 0 : <length of run - 1>
3691 * 16 bit elements: immn = 0, imms = 10 : <length of run - 1>
3692 * 8 bit elements: immn = 0, imms = 110 : <length of run - 1>
3693 * 4 bit elements: immn = 0, imms = 1110 : <length of run - 1>
3694 * 2 bit elements: immn = 0, imms = 11110 : <length of run - 1>
3695 * Notice that immn = 0, imms = 11111x is the only combination
3696 * not covered by one of the above options; this is reserved.
3697 * Further, <length of run - 1> all-ones is a reserved pattern.
3698 *
3699 * In all cases the rotation is by immr % e (and immr is 6 bits).
3700 */
3701
3702 /* First determine the element size */
3703 len = 31 - clz32((immn << 6) | (~imms & 0x3f));
3704 if (len < 1) {
3705 /* This is the immn == 0, imms == 0x11111x case */
3706 return false;
3707 }
3708 e = 1 << len;
3709
3710 levels = e - 1;
3711 s = imms & levels;
3712 r = immr & levels;
3713
3714 if (s == levels) {
3715 /* <length of run - 1> mustn't be all-ones. */
3716 return false;
3717 }
3718
3719 /* Create the value of one element: s+1 set bits rotated
3720 * by r within the element (which is e bits wide)...
3721 */
3722 mask = bitmask64(s + 1);
e167adc9
PM
3723 if (r) {
3724 mask = (mask >> r) | (mask << (e - r));
3725 mask &= bitmask64(e);
3726 }
71b46089
AG
3727 /* ...then replicate the element over the whole 64 bit value */
3728 mask = bitfield_replicate(mask, e);
3729 *result = mask;
3730 return true;
3731}
3732
4ce31af4 3733/* Logical (immediate)
71b46089
AG
3734 * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
3735 * +----+-----+-------------+---+------+------+------+------+
3736 * | sf | opc | 1 0 0 1 0 0 | N | immr | imms | Rn | Rd |
3737 * +----+-----+-------------+---+------+------+------+------+
3738 */
ad7ee8a2
CF
3739static void disas_logic_imm(DisasContext *s, uint32_t insn)
3740{
71b46089
AG
3741 unsigned int sf, opc, is_n, immr, imms, rn, rd;
3742 TCGv_i64 tcg_rd, tcg_rn;
3743 uint64_t wmask;
3744 bool is_and = false;
3745
3746 sf = extract32(insn, 31, 1);
3747 opc = extract32(insn, 29, 2);
3748 is_n = extract32(insn, 22, 1);
3749 immr = extract32(insn, 16, 6);
3750 imms = extract32(insn, 10, 6);
3751 rn = extract32(insn, 5, 5);
3752 rd = extract32(insn, 0, 5);
3753
3754 if (!sf && is_n) {
3755 unallocated_encoding(s);
3756 return;
3757 }
3758
3759 if (opc == 0x3) { /* ANDS */
3760 tcg_rd = cpu_reg(s, rd);
3761 } else {
3762 tcg_rd = cpu_reg_sp(s, rd);
3763 }
3764 tcg_rn = cpu_reg(s, rn);
3765
3766 if (!logic_imm_decode_wmask(&wmask, is_n, imms, immr)) {
3767 /* some immediate field values are reserved */
3768 unallocated_encoding(s);
3769 return;
3770 }
3771
3772 if (!sf) {
3773 wmask &= 0xffffffff;
3774 }
3775
3776 switch (opc) {
3777 case 0x3: /* ANDS */
3778 case 0x0: /* AND */
3779 tcg_gen_andi_i64(tcg_rd, tcg_rn, wmask);
3780 is_and = true;
3781 break;
3782 case 0x1: /* ORR */
3783 tcg_gen_ori_i64(tcg_rd, tcg_rn, wmask);
3784 break;
3785 case 0x2: /* EOR */
3786 tcg_gen_xori_i64(tcg_rd, tcg_rn, wmask);
3787 break;
3788 default:
3789 assert(FALSE); /* must handle all above */
3790 break;
3791 }
3792
3793 if (!sf && !is_and) {
3794 /* zero extend final result; we know we can skip this for AND
3795 * since the immediate had the high 32 bits clear.
3796 */
3797 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3798 }
3799
3800 if (opc == 3) { /* ANDS */
3801 gen_logic_CC(sf, tcg_rd);
3802 }
ad7ee8a2
CF
3803}
3804
ed6ec679 3805/*
4ce31af4 3806 * Move wide (immediate)
ed6ec679
AB
3807 *
3808 * 31 30 29 28 23 22 21 20 5 4 0
3809 * +--+-----+-------------+-----+----------------+------+
3810 * |sf| opc | 1 0 0 1 0 1 | hw | imm16 | Rd |
3811 * +--+-----+-------------+-----+----------------+------+
3812 *
3813 * sf: 0 -> 32 bit, 1 -> 64 bit
3814 * opc: 00 -> N, 10 -> Z, 11 -> K
3815 * hw: shift/16 (0,16, and sf only 32, 48)
3816 */
ad7ee8a2
CF
3817static void disas_movw_imm(DisasContext *s, uint32_t insn)
3818{
ed6ec679
AB
3819 int rd = extract32(insn, 0, 5);
3820 uint64_t imm = extract32(insn, 5, 16);
3821 int sf = extract32(insn, 31, 1);
3822 int opc = extract32(insn, 29, 2);
3823 int pos = extract32(insn, 21, 2) << 4;
3824 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3825 TCGv_i64 tcg_imm;
3826
3827 if (!sf && (pos >= 32)) {
3828 unallocated_encoding(s);
3829 return;
3830 }
3831
3832 switch (opc) {
3833 case 0: /* MOVN */
3834 case 2: /* MOVZ */
3835 imm <<= pos;
3836 if (opc == 0) {
3837 imm = ~imm;
3838 }
3839 if (!sf) {
3840 imm &= 0xffffffffu;
3841 }
3842 tcg_gen_movi_i64(tcg_rd, imm);
3843 break;
3844 case 3: /* MOVK */
3845 tcg_imm = tcg_const_i64(imm);
3846 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16);
3847 tcg_temp_free_i64(tcg_imm);
3848 if (!sf) {
3849 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3850 }
3851 break;
3852 default:
3853 unallocated_encoding(s);
3854 break;
3855 }
ad7ee8a2
CF
3856}
3857
4ce31af4 3858/* Bitfield
88077742
CF
3859 * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
3860 * +----+-----+-------------+---+------+------+------+------+
3861 * | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd |
3862 * +----+-----+-------------+---+------+------+------+------+
3863 */
ad7ee8a2
CF
3864static void disas_bitfield(DisasContext *s, uint32_t insn)
3865{
88077742
CF
3866 unsigned int sf, n, opc, ri, si, rn, rd, bitsize, pos, len;
3867 TCGv_i64 tcg_rd, tcg_tmp;
3868
3869 sf = extract32(insn, 31, 1);
3870 opc = extract32(insn, 29, 2);
3871 n = extract32(insn, 22, 1);
3872 ri = extract32(insn, 16, 6);
3873 si = extract32(insn, 10, 6);
3874 rn = extract32(insn, 5, 5);
3875 rd = extract32(insn, 0, 5);
3876 bitsize = sf ? 64 : 32;
3877
3878 if (sf != n || ri >= bitsize || si >= bitsize || opc > 2) {
3879 unallocated_encoding(s);
3880 return;
3881 }
3882
3883 tcg_rd = cpu_reg(s, rd);
d3a77b42
RH
3884
3885 /* Suppress the zero-extend for !sf. Since RI and SI are constrained
3886 to be smaller than bitsize, we'll never reference data outside the
3887 low 32-bits anyway. */
3888 tcg_tmp = read_cpu_reg(s, rn, 1);
88077742 3889
59a71b4c 3890 /* Recognize simple(r) extractions. */
86c9ab27 3891 if (si >= ri) {
59a71b4c
RH
3892 /* Wd<s-r:0> = Wn<s:r> */
3893 len = (si - ri) + 1;
3894 if (opc == 0) { /* SBFM: ASR, SBFX, SXTB, SXTH, SXTW */
3895 tcg_gen_sextract_i64(tcg_rd, tcg_tmp, ri, len);
ef60151b 3896 goto done;
59a71b4c
RH
3897 } else if (opc == 2) { /* UBFM: UBFX, LSR, UXTB, UXTH */
3898 tcg_gen_extract_i64(tcg_rd, tcg_tmp, ri, len);
9924e858
RH
3899 return;
3900 }
59a71b4c
RH
3901 /* opc == 1, BXFIL fall through to deposit */
3902 tcg_gen_extract_i64(tcg_tmp, tcg_tmp, ri, len);
88077742 3903 pos = 0;
88077742 3904 } else {
59a71b4c
RH
3905 /* Handle the ri > si case with a deposit
3906 * Wd<32+s-r,32-r> = Wn<s:0>
3907 */
88077742 3908 len = si + 1;
59a71b4c 3909 pos = (bitsize - ri) & (bitsize - 1);
88077742
CF
3910 }
3911
59a71b4c
RH
3912 if (opc == 0 && len < ri) {
3913 /* SBFM: sign extend the destination field from len to fill
3914 the balance of the word. Let the deposit below insert all
3915 of those sign bits. */
3916 tcg_gen_sextract_i64(tcg_tmp, tcg_tmp, 0, len);
3917 len = ri;
3918 }
88077742 3919
59a71b4c
RH
3920 if (opc == 1) { /* BFM, BXFIL */
3921 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
3922 } else {
3923 /* SBFM or UBFM: We start with zero, and we haven't modified
3924 any bits outside bitsize, therefore the zero-extension
3925 below is unneeded. */
3926 tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
3927 return;
88077742
CF
3928 }
3929
ef60151b 3930 done:
88077742
CF
3931 if (!sf) { /* zero extend final result */
3932 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3933 }
ad7ee8a2
CF
3934}
3935
4ce31af4 3936/* Extract
e801de93
AG
3937 * 31 30 29 28 23 22 21 20 16 15 10 9 5 4 0
3938 * +----+------+-------------+---+----+------+--------+------+------+
3939 * | sf | op21 | 1 0 0 1 1 1 | N | o0 | Rm | imms | Rn | Rd |
3940 * +----+------+-------------+---+----+------+--------+------+------+
3941 */
ad7ee8a2
CF
3942static void disas_extract(DisasContext *s, uint32_t insn)
3943{
e801de93
AG
3944 unsigned int sf, n, rm, imm, rn, rd, bitsize, op21, op0;
3945
3946 sf = extract32(insn, 31, 1);
3947 n = extract32(insn, 22, 1);
3948 rm = extract32(insn, 16, 5);
3949 imm = extract32(insn, 10, 6);
3950 rn = extract32(insn, 5, 5);
3951 rd = extract32(insn, 0, 5);
3952 op21 = extract32(insn, 29, 2);
3953 op0 = extract32(insn, 21, 1);
3954 bitsize = sf ? 64 : 32;
3955
3956 if (sf != n || op21 || op0 || imm >= bitsize) {
3957 unallocated_encoding(s);
3958 } else {
3959 TCGv_i64 tcg_rd, tcg_rm, tcg_rn;
3960
3961 tcg_rd = cpu_reg(s, rd);
3962
8fb0ad8e 3963 if (unlikely(imm == 0)) {
e801de93
AG
3964 /* tcg shl_i32/shl_i64 is undefined for 32/64 bit shifts,
3965 * so an extract from bit 0 is a special case.
3966 */
3967 if (sf) {
3968 tcg_gen_mov_i64(tcg_rd, cpu_reg(s, rm));
3969 } else {
3970 tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rm));
3971 }
8fb0ad8e
RH
3972 } else if (rm == rn) { /* ROR */
3973 tcg_rm = cpu_reg(s, rm);
3974 if (sf) {
3975 tcg_gen_rotri_i64(tcg_rd, tcg_rm, imm);
3976 } else {
3977 TCGv_i32 tmp = tcg_temp_new_i32();
3978 tcg_gen_extrl_i64_i32(tmp, tcg_rm);
3979 tcg_gen_rotri_i32(tmp, tmp, imm);
3980 tcg_gen_extu_i32_i64(tcg_rd, tmp);
3981 tcg_temp_free_i32(tmp);
3982 }
3983 } else {
3984 tcg_rm = read_cpu_reg(s, rm, sf);
3985 tcg_rn = read_cpu_reg(s, rn, sf);
3986 tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
3987 tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
3988 tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
3989 if (!sf) {
3990 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3991 }
e801de93 3992 }
e801de93 3993 }
ad7ee8a2
CF
3994}
3995
4ce31af4 3996/* Data processing - immediate */
ad7ee8a2
CF
3997static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
3998{
3999 switch (extract32(insn, 23, 6)) {
4000 case 0x20: case 0x21: /* PC-rel. addressing */
4001 disas_pc_rel_adr(s, insn);
4002 break;
4003 case 0x22: case 0x23: /* Add/subtract (immediate) */
4004 disas_add_sub_imm(s, insn);
4005 break;
4006 case 0x24: /* Logical (immediate) */
4007 disas_logic_imm(s, insn);
4008 break;
4009 case 0x25: /* Move wide (immediate) */
4010 disas_movw_imm(s, insn);
4011 break;
4012 case 0x26: /* Bitfield */
4013 disas_bitfield(s, insn);
4014 break;
4015 case 0x27: /* Extract */
4016 disas_extract(s, insn);
4017 break;
4018 default:
4019 unallocated_encoding(s);
4020 break;
4021 }
4022}
4023
832ffa1c
AG
4024/* Shift a TCGv src by TCGv shift_amount, put result in dst.
4025 * Note that it is the caller's responsibility to ensure that the
4026 * shift amount is in range (ie 0..31 or 0..63) and provide the ARM
4027 * mandated semantics for out of range shifts.
4028 */
4029static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
4030 enum a64_shift_type shift_type, TCGv_i64 shift_amount)
4031{
4032 switch (shift_type) {
4033 case A64_SHIFT_TYPE_LSL:
4034 tcg_gen_shl_i64(dst, src, shift_amount);
4035 break;
4036 case A64_SHIFT_TYPE_LSR:
4037 tcg_gen_shr_i64(dst, src, shift_amount);
4038 break;
4039 case A64_SHIFT_TYPE_ASR:
4040 if (!sf) {
4041 tcg_gen_ext32s_i64(dst, src);
4042 }
4043 tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
4044 break;
4045 case A64_SHIFT_TYPE_ROR:
4046 if (sf) {
4047 tcg_gen_rotr_i64(dst, src, shift_amount);
4048 } else {
4049 TCGv_i32 t0, t1;
4050 t0 = tcg_temp_new_i32();
4051 t1 = tcg_temp_new_i32();
ecc7b3aa
RH
4052 tcg_gen_extrl_i64_i32(t0, src);
4053 tcg_gen_extrl_i64_i32(t1, shift_amount);
832ffa1c
AG
4054 tcg_gen_rotr_i32(t0, t0, t1);
4055 tcg_gen_extu_i32_i64(dst, t0);
4056 tcg_temp_free_i32(t0);
4057 tcg_temp_free_i32(t1);
4058 }
4059 break;
4060 default:
4061 assert(FALSE); /* all shift types should be handled */
4062 break;
4063 }
4064
4065 if (!sf) { /* zero extend final result */
4066 tcg_gen_ext32u_i64(dst, dst);
4067 }
4068}
4069
4070/* Shift a TCGv src by immediate, put result in dst.
4071 * The shift amount must be in range (this should always be true as the
4072 * relevant instructions will UNDEF on bad shift immediates).
4073 */
4074static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
4075 enum a64_shift_type shift_type, unsigned int shift_i)
4076{
4077 assert(shift_i < (sf ? 64 : 32));
4078
4079 if (shift_i == 0) {
4080 tcg_gen_mov_i64(dst, src);
4081 } else {
4082 TCGv_i64 shift_const;
4083
4084 shift_const = tcg_const_i64(shift_i);
4085 shift_reg(dst, src, sf, shift_type, shift_const);
4086 tcg_temp_free_i64(shift_const);
4087 }
4088}
4089
4ce31af4 4090/* Logical (shifted register)
832ffa1c
AG
4091 * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
4092 * +----+-----+-----------+-------+---+------+--------+------+------+
4093 * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd |
4094 * +----+-----+-----------+-------+---+------+--------+------+------+
4095 */
ad7ee8a2
CF
4096static void disas_logic_reg(DisasContext *s, uint32_t insn)
4097{
832ffa1c
AG
4098 TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
4099 unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
4100
4101 sf = extract32(insn, 31, 1);
4102 opc = extract32(insn, 29, 2);
4103 shift_type = extract32(insn, 22, 2);
4104 invert = extract32(insn, 21, 1);
4105 rm = extract32(insn, 16, 5);
4106 shift_amount = extract32(insn, 10, 6);
4107 rn = extract32(insn, 5, 5);
4108 rd = extract32(insn, 0, 5);
4109
4110 if (!sf && (shift_amount & (1 << 5))) {
4111 unallocated_encoding(s);
4112 return;
4113 }
4114
4115 tcg_rd = cpu_reg(s, rd);
4116
4117 if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
4118 /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
4119 * register-register MOV and MVN, so it is worth special casing.
4120 */
4121 tcg_rm = cpu_reg(s, rm);
4122 if (invert) {
4123 tcg_gen_not_i64(tcg_rd, tcg_rm);
4124 if (!sf) {
4125 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4126 }
4127 } else {
4128 if (sf) {
4129 tcg_gen_mov_i64(tcg_rd, tcg_rm);
4130 } else {
4131 tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
4132 }
4133 }
4134 return;
4135 }
4136
4137 tcg_rm = read_cpu_reg(s, rm, sf);
4138
4139 if (shift_amount) {
4140 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
4141 }
4142
4143 tcg_rn = cpu_reg(s, rn);
4144
4145 switch (opc | (invert << 2)) {
4146 case 0: /* AND */
4147 case 3: /* ANDS */
4148 tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
4149 break;
4150 case 1: /* ORR */
4151 tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
4152 break;
4153 case 2: /* EOR */
4154 tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
4155 break;
4156 case 4: /* BIC */
4157 case 7: /* BICS */
4158 tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
4159 break;
4160 case 5: /* ORN */
4161 tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
4162 break;
4163 case 6: /* EON */
4164 tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
4165 break;
4166 default:
4167 assert(FALSE);
4168 break;
4169 }
4170
4171 if (!sf) {
4172 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4173 }
4174
4175 if (opc == 3) {
4176 gen_logic_CC(sf, tcg_rd);
4177 }
ad7ee8a2
CF
4178}
4179
b0ff21b4 4180/*
4ce31af4 4181 * Add/subtract (extended register)
b0ff21b4
AB
4182 *
4183 * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0|
4184 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
4185 * |sf|op| S| 0 1 0 1 1 | opt | 1| Rm |option| imm3 | Rn | Rd |
4186 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
4187 *
4188 * sf: 0 -> 32bit, 1 -> 64bit
4189 * op: 0 -> add , 1 -> sub
4190 * S: 1 -> set flags
4191 * opt: 00
4192 * option: extension type (see DecodeRegExtend)
4193 * imm3: optional shift to Rm
4194 *
4195 * Rd = Rn + LSL(extend(Rm), amount)
4196 */
ad7ee8a2
CF
4197static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
4198{
b0ff21b4
AB
4199 int rd = extract32(insn, 0, 5);
4200 int rn = extract32(insn, 5, 5);
4201 int imm3 = extract32(insn, 10, 3);
4202 int option = extract32(insn, 13, 3);
4203 int rm = extract32(insn, 16, 5);
4204 bool setflags = extract32(insn, 29, 1);
4205 bool sub_op = extract32(insn, 30, 1);
4206 bool sf = extract32(insn, 31, 1);
4207
4208 TCGv_i64 tcg_rm, tcg_rn; /* temps */
4209 TCGv_i64 tcg_rd;
4210 TCGv_i64 tcg_result;
4211
4212 if (imm3 > 4) {
4213 unallocated_encoding(s);
4214 return;
4215 }
4216
4217 /* non-flag setting ops may use SP */
4218 if (!setflags) {
b0ff21b4
AB
4219 tcg_rd = cpu_reg_sp(s, rd);
4220 } else {
b0ff21b4
AB
4221 tcg_rd = cpu_reg(s, rd);
4222 }
cf4ab1af 4223 tcg_rn = read_cpu_reg_sp(s, rn, sf);
b0ff21b4
AB
4224
4225 tcg_rm = read_cpu_reg(s, rm, sf);
4226 ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
4227
4228 tcg_result = tcg_temp_new_i64();
4229
4230 if (!setflags) {
4231 if (sub_op) {
4232 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
4233 } else {
4234 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
4235 }
4236 } else {
4237 if (sub_op) {
4238 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
4239 } else {
4240 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
4241 }
4242 }
4243
4244 if (sf) {
4245 tcg_gen_mov_i64(tcg_rd, tcg_result);
4246 } else {
4247 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
4248 }
4249
4250 tcg_temp_free_i64(tcg_result);
ad7ee8a2
CF
4251}
4252
b0ff21b4 4253/*
4ce31af4 4254 * Add/subtract (shifted register)
b0ff21b4
AB
4255 *
4256 * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
4257 * +--+--+--+-----------+-----+--+-------+---------+------+------+
4258 * |sf|op| S| 0 1 0 1 1 |shift| 0| Rm | imm6 | Rn | Rd |
4259 * +--+--+--+-----------+-----+--+-------+---------+------+------+
4260 *
4261 * sf: 0 -> 32bit, 1 -> 64bit
4262 * op: 0 -> add , 1 -> sub
4263 * S: 1 -> set flags
4264 * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
4265 * imm6: Shift amount to apply to Rm before the add/sub
4266 */
ad7ee8a2
CF
4267static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
4268{
b0ff21b4
AB
4269 int rd = extract32(insn, 0, 5);
4270 int rn = extract32(insn, 5, 5);
4271 int imm6 = extract32(insn, 10, 6);
4272 int rm = extract32(insn, 16, 5);
4273 int shift_type = extract32(insn, 22, 2);
4274 bool setflags = extract32(insn, 29, 1);
4275 bool sub_op = extract32(insn, 30, 1);
4276 bool sf = extract32(insn, 31, 1);
4277
4278 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4279 TCGv_i64 tcg_rn, tcg_rm;
4280 TCGv_i64 tcg_result;
4281
4282 if ((shift_type == 3) || (!sf && (imm6 > 31))) {
4283 unallocated_encoding(s);
4284 return;
4285 }
4286
4287 tcg_rn = read_cpu_reg(s, rn, sf);
4288 tcg_rm = read_cpu_reg(s, rm, sf);
4289
4290 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
4291
4292 tcg_result = tcg_temp_new_i64();
4293
4294 if (!setflags) {
4295 if (sub_op) {
4296 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
4297 } else {
4298 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
4299 }
4300 } else {
4301 if (sub_op) {
4302 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
4303 } else {
4304 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
4305 }
4306 }
4307
4308 if (sf) {
4309 tcg_gen_mov_i64(tcg_rd, tcg_result);
4310 } else {
4311 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
4312 }
4313
4314 tcg_temp_free_i64(tcg_result);
ad7ee8a2
CF
4315}
4316
4ce31af4
PM
4317/* Data-processing (3 source)
4318 *
4319 * 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0
4320 * +--+------+-----------+------+------+----+------+------+------+
4321 * |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd |
4322 * +--+------+-----------+------+------+----+------+------+------+
52c8b9af 4323 */
ad7ee8a2
CF
4324static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
4325{
52c8b9af
AG
4326 int rd = extract32(insn, 0, 5);
4327 int rn = extract32(insn, 5, 5);
4328 int ra = extract32(insn, 10, 5);
4329 int rm = extract32(insn, 16, 5);
4330 int op_id = (extract32(insn, 29, 3) << 4) |
4331 (extract32(insn, 21, 3) << 1) |
4332 extract32(insn, 15, 1);
4333 bool sf = extract32(insn, 31, 1);
4334 bool is_sub = extract32(op_id, 0, 1);
4335 bool is_high = extract32(op_id, 2, 1);
4336 bool is_signed = false;
4337 TCGv_i64 tcg_op1;
4338 TCGv_i64 tcg_op2;
4339 TCGv_i64 tcg_tmp;
4340
4341 /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
4342 switch (op_id) {
4343 case 0x42: /* SMADDL */
4344 case 0x43: /* SMSUBL */
4345 case 0x44: /* SMULH */
4346 is_signed = true;
4347 break;
4348 case 0x0: /* MADD (32bit) */
4349 case 0x1: /* MSUB (32bit) */
4350 case 0x40: /* MADD (64bit) */
4351 case 0x41: /* MSUB (64bit) */
4352 case 0x4a: /* UMADDL */
4353 case 0x4b: /* UMSUBL */
4354 case 0x4c: /* UMULH */
4355 break;
4356 default:
4357 unallocated_encoding(s);
4358 return;
4359 }
4360
4361 if (is_high) {
4362 TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
4363 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4364 TCGv_i64 tcg_rn = cpu_reg(s, rn);
4365 TCGv_i64 tcg_rm = cpu_reg(s, rm);
4366
4367 if (is_signed) {
4368 tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
4369 } else {
4370 tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
4371 }
4372
4373 tcg_temp_free_i64(low_bits);
4374 return;
4375 }
4376
4377 tcg_op1 = tcg_temp_new_i64();
4378 tcg_op2 = tcg_temp_new_i64();
4379 tcg_tmp = tcg_temp_new_i64();
4380
4381 if (op_id < 0x42) {
4382 tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
4383 tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
4384 } else {
4385 if (is_signed) {
4386 tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
4387 tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
4388 } else {
4389 tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
4390 tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
4391 }
4392 }
4393
4394 if (ra == 31 && !is_sub) {
4395 /* Special-case MADD with rA == XZR; it is the standard MUL alias */
4396 tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
4397 } else {
4398 tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
4399 if (is_sub) {
4400 tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
4401 } else {
4402 tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
4403 }
4404 }
4405
4406 if (!sf) {
4407 tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
4408 }
4409
4410 tcg_temp_free_i64(tcg_op1);
4411 tcg_temp_free_i64(tcg_op2);
4412 tcg_temp_free_i64(tcg_tmp);
ad7ee8a2
CF
4413}
4414
4ce31af4 4415/* Add/subtract (with carry)
643dbb07
CF
4416 * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
4417 * +--+--+--+------------------------+------+---------+------+-----+
4418 * |sf|op| S| 1 1 0 1 0 0 0 0 | rm | opcode2 | Rn | Rd |
4419 * +--+--+--+------------------------+------+---------+------+-----+
4420 * [000000]
4421 */
4422
ad7ee8a2
CF
4423static void disas_adc_sbc(DisasContext *s, uint32_t insn)
4424{
643dbb07
CF
4425 unsigned int sf, op, setflags, rm, rn, rd;
4426 TCGv_i64 tcg_y, tcg_rn, tcg_rd;
4427
4428 if (extract32(insn, 10, 6) != 0) {
4429 unallocated_encoding(s);
4430 return;
4431 }
4432
4433 sf = extract32(insn, 31, 1);
4434 op = extract32(insn, 30, 1);
4435 setflags = extract32(insn, 29, 1);
4436 rm = extract32(insn, 16, 5);
4437 rn = extract32(insn, 5, 5);
4438 rd = extract32(insn, 0, 5);
4439
4440 tcg_rd = cpu_reg(s, rd);
4441 tcg_rn = cpu_reg(s, rn);
4442
4443 if (op) {
4444 tcg_y = new_tmp_a64(s);
4445 tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
4446 } else {
4447 tcg_y = cpu_reg(s, rm);
4448 }
4449
4450 if (setflags) {
4451 gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
4452 } else {
4453 gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
4454 }
ad7ee8a2
CF
4455}
4456
4ce31af4 4457/* Conditional compare (immediate / register)
750813cf
CF
4458 * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
4459 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
4460 * |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv |
4461 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
4462 * [1] y [0] [0]
4463 */
4464static void disas_cc(DisasContext *s, uint32_t insn)
ad7ee8a2 4465{
750813cf 4466 unsigned int sf, op, y, cond, rn, nzcv, is_imm;
7dd03d77 4467 TCGv_i32 tcg_t0, tcg_t1, tcg_t2;
750813cf 4468 TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
7dd03d77 4469 DisasCompare c;
ad7ee8a2 4470
750813cf
CF
4471 if (!extract32(insn, 29, 1)) {
4472 unallocated_encoding(s);
4473 return;
4474 }
4475 if (insn & (1 << 10 | 1 << 4)) {
4476 unallocated_encoding(s);
4477 return;
4478 }
4479 sf = extract32(insn, 31, 1);
4480 op = extract32(insn, 30, 1);
4481 is_imm = extract32(insn, 11, 1);
4482 y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */
4483 cond = extract32(insn, 12, 4);
4484 rn = extract32(insn, 5, 5);
4485 nzcv = extract32(insn, 0, 4);
4486
7dd03d77
RH
4487 /* Set T0 = !COND. */
4488 tcg_t0 = tcg_temp_new_i32();
4489 arm_test_cc(&c, cond);
4490 tcg_gen_setcondi_i32(tcg_invert_cond(c.cond), tcg_t0, c.value, 0);
4491 arm_free_cc(&c);
4492
4493 /* Load the arguments for the new comparison. */
750813cf
CF
4494 if (is_imm) {
4495 tcg_y = new_tmp_a64(s);
4496 tcg_gen_movi_i64(tcg_y, y);
4497 } else {
4498 tcg_y = cpu_reg(s, y);
4499 }
4500 tcg_rn = cpu_reg(s, rn);
4501
7dd03d77 4502 /* Set the flags for the new comparison. */
750813cf
CF
4503 tcg_tmp = tcg_temp_new_i64();
4504 if (op) {
4505 gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
4506 } else {
4507 gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
4508 }
4509 tcg_temp_free_i64(tcg_tmp);
4510
7dd03d77
RH
4511 /* If COND was false, force the flags to #nzcv. Compute two masks
4512 * to help with this: T1 = (COND ? 0 : -1), T2 = (COND ? -1 : 0).
4513 * For tcg hosts that support ANDC, we can make do with just T1.
4514 * In either case, allow the tcg optimizer to delete any unused mask.
4515 */
4516 tcg_t1 = tcg_temp_new_i32();
4517 tcg_t2 = tcg_temp_new_i32();
4518 tcg_gen_neg_i32(tcg_t1, tcg_t0);
4519 tcg_gen_subi_i32(tcg_t2, tcg_t0, 1);
4520
4521 if (nzcv & 8) { /* N */
4522 tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1);
4523 } else {
4524 if (TCG_TARGET_HAS_andc_i32) {
4525 tcg_gen_andc_i32(cpu_NF, cpu_NF, tcg_t1);
4526 } else {
4527 tcg_gen_and_i32(cpu_NF, cpu_NF, tcg_t2);
4528 }
4529 }
4530 if (nzcv & 4) { /* Z */
4531 if (TCG_TARGET_HAS_andc_i32) {
4532 tcg_gen_andc_i32(cpu_ZF, cpu_ZF, tcg_t1);
4533 } else {
4534 tcg_gen_and_i32(cpu_ZF, cpu_ZF, tcg_t2);
4535 }
4536 } else {
4537 tcg_gen_or_i32(cpu_ZF, cpu_ZF, tcg_t0);
4538 }
4539 if (nzcv & 2) { /* C */
4540 tcg_gen_or_i32(cpu_CF, cpu_CF, tcg_t0);
4541 } else {
4542 if (TCG_TARGET_HAS_andc_i32) {
4543 tcg_gen_andc_i32(cpu_CF, cpu_CF, tcg_t1);
4544 } else {
4545 tcg_gen_and_i32(cpu_CF, cpu_CF, tcg_t2);
4546 }
4547 }
4548 if (nzcv & 1) { /* V */
4549 tcg_gen_or_i32(cpu_VF, cpu_VF, tcg_t1);
4550 } else {
4551 if (TCG_TARGET_HAS_andc_i32) {
4552 tcg_gen_andc_i32(cpu_VF, cpu_VF, tcg_t1);
4553 } else {
4554 tcg_gen_and_i32(cpu_VF, cpu_VF, tcg_t2);
4555 }
750813cf 4556 }
7dd03d77
RH
4557 tcg_temp_free_i32(tcg_t0);
4558 tcg_temp_free_i32(tcg_t1);
4559 tcg_temp_free_i32(tcg_t2);
ad7ee8a2
CF
4560}
4561
4ce31af4 4562/* Conditional select
e952d8c7
CF
4563 * 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0
4564 * +----+----+---+-----------------+------+------+-----+------+------+
4565 * | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd |
4566 * +----+----+---+-----------------+------+------+-----+------+------+
4567 */
ad7ee8a2
CF
4568static void disas_cond_select(DisasContext *s, uint32_t insn)
4569{
e952d8c7 4570 unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
259cb684
RH
4571 TCGv_i64 tcg_rd, zero;
4572 DisasCompare64 c;
e952d8c7
CF
4573
4574 if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
4575 /* S == 1 or op2<1> == 1 */
4576 unallocated_encoding(s);
4577 return;
4578 }
4579 sf = extract32(insn, 31, 1);
4580 else_inv = extract32(insn, 30, 1);
4581 rm = extract32(insn, 16, 5);
4582 cond = extract32(insn, 12, 4);
4583 else_inc = extract32(insn, 10, 1);
4584 rn = extract32(insn, 5, 5);
4585 rd = extract32(insn, 0, 5);
4586
e952d8c7
CF
4587 tcg_rd = cpu_reg(s, rd);
4588
259cb684
RH
4589 a64_test_cc(&c, cond);
4590 zero = tcg_const_i64(0);
e952d8c7 4591
259cb684
RH
4592 if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) {
4593 /* CSET & CSETM. */
4594 tcg_gen_setcond_i64(tcg_invert_cond(c.cond), tcg_rd, c.value, zero);
4595 if (else_inv) {
4596 tcg_gen_neg_i64(tcg_rd, tcg_rd);
4597 }
4598 } else {
4599 TCGv_i64 t_true = cpu_reg(s, rn);
4600 TCGv_i64 t_false = read_cpu_reg(s, rm, 1);
e952d8c7 4601 if (else_inv && else_inc) {
259cb684 4602 tcg_gen_neg_i64(t_false, t_false);
e952d8c7 4603 } else if (else_inv) {
259cb684 4604 tcg_gen_not_i64(t_false, t_false);
e952d8c7 4605 } else if (else_inc) {
259cb684 4606 tcg_gen_addi_i64(t_false, t_false, 1);
e952d8c7 4607 }
259cb684
RH
4608 tcg_gen_movcond_i64(c.cond, tcg_rd, c.value, zero, t_true, t_false);
4609 }
4610
4611 tcg_temp_free_i64(zero);
4612 a64_free_cc(&c);
4613
4614 if (!sf) {
4615 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
e952d8c7 4616 }
ad7ee8a2
CF
4617}
4618
680ead21
CF
4619static void handle_clz(DisasContext *s, unsigned int sf,
4620 unsigned int rn, unsigned int rd)
4621{
4622 TCGv_i64 tcg_rd, tcg_rn;
4623 tcg_rd = cpu_reg(s, rd);
4624 tcg_rn = cpu_reg(s, rn);
4625
4626 if (sf) {
7539a012 4627 tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
680ead21
CF
4628 } else {
4629 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
ecc7b3aa 4630 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
7539a012 4631 tcg_gen_clzi_i32(tcg_tmp32, tcg_tmp32, 32);
680ead21
CF
4632 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
4633 tcg_temp_free_i32(tcg_tmp32);
4634 }
4635}
4636
e80c5020
CF
4637static void handle_cls(DisasContext *s, unsigned int sf,
4638 unsigned int rn, unsigned int rd)
4639{
4640 TCGv_i64 tcg_rd, tcg_rn;
4641 tcg_rd = cpu_reg(s, rd);
4642 tcg_rn = cpu_reg(s, rn);
4643
4644 if (sf) {
bc21dbcc 4645 tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
e80c5020
CF
4646 } else {
4647 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
ecc7b3aa 4648 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
bc21dbcc 4649 tcg_gen_clrsb_i32(tcg_tmp32, tcg_tmp32);
e80c5020
CF
4650 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
4651 tcg_temp_free_i32(tcg_tmp32);
4652 }
4653}
4654
82e14b02
AG
4655static void handle_rbit(DisasContext *s, unsigned int sf,
4656 unsigned int rn, unsigned int rd)
4657{
4658 TCGv_i64 tcg_rd, tcg_rn;
4659 tcg_rd = cpu_reg(s, rd);
4660 tcg_rn = cpu_reg(s, rn);
4661
4662 if (sf) {
4663 gen_helper_rbit64(tcg_rd, tcg_rn);
4664 } else {
4665 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
ecc7b3aa 4666 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
82e14b02
AG
4667 gen_helper_rbit(tcg_tmp32, tcg_tmp32);
4668 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
4669 tcg_temp_free_i32(tcg_tmp32);
4670 }
4671}
4672
4ce31af4 4673/* REV with sf==1, opcode==3 ("REV64") */
45323209
CF
4674static void handle_rev64(DisasContext *s, unsigned int sf,
4675 unsigned int rn, unsigned int rd)
4676{
4677 if (!sf) {
4678 unallocated_encoding(s);
4679 return;
4680 }
4681 tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
4682}
4683
4ce31af4
PM
4684/* REV with sf==0, opcode==2
4685 * REV32 (sf==1, opcode==2)
45323209
CF
4686 */
4687static void handle_rev32(DisasContext *s, unsigned int sf,
4688 unsigned int rn, unsigned int rd)
4689{
4690 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4691
4692 if (sf) {
4693 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
4694 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
4695
4696 /* bswap32_i64 requires zero high word */
4697 tcg_gen_ext32u_i64(tcg_tmp, tcg_rn);
4698 tcg_gen_bswap32_i64(tcg_rd, tcg_tmp);
4699 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
4700 tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
4701 tcg_gen_concat32_i64(tcg_rd, tcg_rd, tcg_tmp);
4702
4703 tcg_temp_free_i64(tcg_tmp);
4704 } else {
4705 tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rn));
4706 tcg_gen_bswap32_i64(tcg_rd, tcg_rd);
4707 }
4708}
4709
4ce31af4 4710/* REV16 (opcode==1) */
45323209
CF
4711static void handle_rev16(DisasContext *s, unsigned int sf,
4712 unsigned int rn, unsigned int rd)
4713{
4714 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4715 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
4716 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
abb1066d 4717 TCGv_i64 mask = tcg_const_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff);
45323209 4718
abb1066d
RH
4719 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8);
4720 tcg_gen_and_i64(tcg_rd, tcg_rn, mask);
4721 tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask);
4722 tcg_gen_shli_i64(tcg_rd, tcg_rd, 8);
4723 tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp);
45323209 4724
e4256c3c 4725 tcg_temp_free_i64(mask);
45323209
CF
4726 tcg_temp_free_i64(tcg_tmp);
4727}
4728
4ce31af4 4729/* Data-processing (1 source)
680ead21
CF
4730 * 31 30 29 28 21 20 16 15 10 9 5 4 0
4731 * +----+---+---+-----------------+---------+--------+------+------+
4732 * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd |
4733 * +----+---+---+-----------------+---------+--------+------+------+
4734 */
ad7ee8a2
CF
4735static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
4736{
18de2813 4737 unsigned int sf, opcode, opcode2, rn, rd;
95ebd99d 4738 TCGv_i64 tcg_rd;
680ead21 4739
18de2813 4740 if (extract32(insn, 29, 1)) {
680ead21
CF
4741 unallocated_encoding(s);
4742 return;
4743 }
4744
4745 sf = extract32(insn, 31, 1);
4746 opcode = extract32(insn, 10, 6);
18de2813 4747 opcode2 = extract32(insn, 16, 5);
680ead21
CF
4748 rn = extract32(insn, 5, 5);
4749 rd = extract32(insn, 0, 5);
4750
18de2813
RH
4751#define MAP(SF, O2, O1) ((SF) | (O1 << 1) | (O2 << 7))
4752
4753 switch (MAP(sf, opcode2, opcode)) {
4754 case MAP(0, 0x00, 0x00): /* RBIT */
4755 case MAP(1, 0x00, 0x00):
82e14b02
AG
4756 handle_rbit(s, sf, rn, rd);
4757 break;
18de2813
RH
4758 case MAP(0, 0x00, 0x01): /* REV16 */
4759 case MAP(1, 0x00, 0x01):
45323209
CF
4760 handle_rev16(s, sf, rn, rd);
4761 break;
18de2813
RH
4762 case MAP(0, 0x00, 0x02): /* REV/REV32 */
4763 case MAP(1, 0x00, 0x02):
45323209
CF
4764 handle_rev32(s, sf, rn, rd);
4765 break;
18de2813 4766 case MAP(1, 0x00, 0x03): /* REV64 */
45323209 4767 handle_rev64(s, sf, rn, rd);
680ead21 4768 break;
18de2813
RH
4769 case MAP(0, 0x00, 0x04): /* CLZ */
4770 case MAP(1, 0x00, 0x04):
680ead21
CF
4771 handle_clz(s, sf, rn, rd);
4772 break;
18de2813
RH
4773 case MAP(0, 0x00, 0x05): /* CLS */
4774 case MAP(1, 0x00, 0x05):
e80c5020 4775 handle_cls(s, sf, rn, rd);
680ead21 4776 break;
95ebd99d
RH
4777 case MAP(1, 0x01, 0x00): /* PACIA */
4778 if (s->pauth_active) {
4779 tcg_rd = cpu_reg(s, rd);
4780 gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4781 } else if (!dc_isar_feature(aa64_pauth, s)) {
4782 goto do_unallocated;
4783 }
4784 break;
4785 case MAP(1, 0x01, 0x01): /* PACIB */
4786 if (s->pauth_active) {
4787 tcg_rd = cpu_reg(s, rd);
4788 gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4789 } else if (!dc_isar_feature(aa64_pauth, s)) {
4790 goto do_unallocated;
4791 }
4792 break;
4793 case MAP(1, 0x01, 0x02): /* PACDA */
4794 if (s->pauth_active) {
4795 tcg_rd = cpu_reg(s, rd);
4796 gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4797 } else if (!dc_isar_feature(aa64_pauth, s)) {
4798 goto do_unallocated;
4799 }
4800 break;
4801 case MAP(1, 0x01, 0x03): /* PACDB */
4802 if (s->pauth_active) {
4803 tcg_rd = cpu_reg(s, rd);
4804 gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4805 } else if (!dc_isar_feature(aa64_pauth, s)) {
4806 goto do_unallocated;
4807 }
4808 break;
4809 case MAP(1, 0x01, 0x04): /* AUTIA */
4810 if (s->pauth_active) {
4811 tcg_rd = cpu_reg(s, rd);
4812 gen_helper_autia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4813 } else if (!dc_isar_feature(aa64_pauth, s)) {
4814 goto do_unallocated;
4815 }
4816 break;
4817 case MAP(1, 0x01, 0x05): /* AUTIB */
4818 if (s->pauth_active) {
4819 tcg_rd = cpu_reg(s, rd);
4820 gen_helper_autib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4821 } else if (!dc_isar_feature(aa64_pauth, s)) {
4822 goto do_unallocated;
4823 }
4824 break;
4825 case MAP(1, 0x01, 0x06): /* AUTDA */
4826 if (s->pauth_active) {
4827 tcg_rd = cpu_reg(s, rd);
4828 gen_helper_autda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4829 } else if (!dc_isar_feature(aa64_pauth, s)) {
4830 goto do_unallocated;
4831 }
4832 break;
4833 case MAP(1, 0x01, 0x07): /* AUTDB */
4834 if (s->pauth_active) {
4835 tcg_rd = cpu_reg(s, rd);
4836 gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
4837 } else if (!dc_isar_feature(aa64_pauth, s)) {
4838 goto do_unallocated;
4839 }
4840 break;
4841 case MAP(1, 0x01, 0x08): /* PACIZA */
4842 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4843 goto do_unallocated;
4844 } else if (s->pauth_active) {
4845 tcg_rd = cpu_reg(s, rd);
4846 gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4847 }
4848 break;
4849 case MAP(1, 0x01, 0x09): /* PACIZB */
4850 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4851 goto do_unallocated;
4852 } else if (s->pauth_active) {
4853 tcg_rd = cpu_reg(s, rd);
4854 gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4855 }
4856 break;
4857 case MAP(1, 0x01, 0x0a): /* PACDZA */
4858 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4859 goto do_unallocated;
4860 } else if (s->pauth_active) {
4861 tcg_rd = cpu_reg(s, rd);
4862 gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4863 }
4864 break;
4865 case MAP(1, 0x01, 0x0b): /* PACDZB */
4866 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4867 goto do_unallocated;
4868 } else if (s->pauth_active) {
4869 tcg_rd = cpu_reg(s, rd);
4870 gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4871 }
4872 break;
4873 case MAP(1, 0x01, 0x0c): /* AUTIZA */
4874 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4875 goto do_unallocated;
4876 } else if (s->pauth_active) {
4877 tcg_rd = cpu_reg(s, rd);
4878 gen_helper_autia(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4879 }
4880 break;
4881 case MAP(1, 0x01, 0x0d): /* AUTIZB */
4882 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4883 goto do_unallocated;
4884 } else if (s->pauth_active) {
4885 tcg_rd = cpu_reg(s, rd);
4886 gen_helper_autib(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4887 }
4888 break;
4889 case MAP(1, 0x01, 0x0e): /* AUTDZA */
4890 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4891 goto do_unallocated;
4892 } else if (s->pauth_active) {
4893 tcg_rd = cpu_reg(s, rd);
4894 gen_helper_autda(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4895 }
4896 break;
4897 case MAP(1, 0x01, 0x0f): /* AUTDZB */
4898 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4899 goto do_unallocated;
4900 } else if (s->pauth_active) {
4901 tcg_rd = cpu_reg(s, rd);
4902 gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
4903 }
4904 break;
4905 case MAP(1, 0x01, 0x10): /* XPACI */
4906 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4907 goto do_unallocated;
4908 } else if (s->pauth_active) {
4909 tcg_rd = cpu_reg(s, rd);
4910 gen_helper_xpaci(tcg_rd, cpu_env, tcg_rd);
4911 }
4912 break;
4913 case MAP(1, 0x01, 0x11): /* XPACD */
4914 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
4915 goto do_unallocated;
4916 } else if (s->pauth_active) {
4917 tcg_rd = cpu_reg(s, rd);
4918 gen_helper_xpacd(tcg_rd, cpu_env, tcg_rd);
4919 }
4920 break;
18de2813 4921 default:
95ebd99d 4922 do_unallocated:
18de2813
RH
4923 unallocated_encoding(s);
4924 break;
680ead21 4925 }
18de2813
RH
4926
4927#undef MAP
ad7ee8a2
CF
4928}
4929
8220e911
AG
4930static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
4931 unsigned int rm, unsigned int rn, unsigned int rd)
4932{
4933 TCGv_i64 tcg_n, tcg_m, tcg_rd;
4934 tcg_rd = cpu_reg(s, rd);
4935
4936 if (!sf && is_signed) {
4937 tcg_n = new_tmp_a64(s);
4938 tcg_m = new_tmp_a64(s);
4939 tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
4940 tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
4941 } else {
4942 tcg_n = read_cpu_reg(s, rn, sf);
4943 tcg_m = read_cpu_reg(s, rm, sf);
4944 }
4945
4946 if (is_signed) {
4947 gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
4948 } else {
4949 gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
4950 }
4951
4952 if (!sf) { /* zero extend final result */
4953 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4954 }
4955}
4956
4ce31af4 4957/* LSLV, LSRV, ASRV, RORV */
6c1adc91
AG
4958static void handle_shift_reg(DisasContext *s,
4959 enum a64_shift_type shift_type, unsigned int sf,
4960 unsigned int rm, unsigned int rn, unsigned int rd)
4961{
4962 TCGv_i64 tcg_shift = tcg_temp_new_i64();
4963 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4964 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
4965
4966 tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
4967 shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
4968 tcg_temp_free_i64(tcg_shift);
4969}
4970
130f2e7d
PM
4971/* CRC32[BHWX], CRC32C[BHWX] */
4972static void handle_crc32(DisasContext *s,
4973 unsigned int sf, unsigned int sz, bool crc32c,
4974 unsigned int rm, unsigned int rn, unsigned int rd)
4975{
4976 TCGv_i64 tcg_acc, tcg_val;
4977 TCGv_i32 tcg_bytes;
4978
962fcbf2 4979 if (!dc_isar_feature(aa64_crc32, s)
130f2e7d
PM
4980 || (sf == 1 && sz != 3)
4981 || (sf == 0 && sz == 3)) {
4982 unallocated_encoding(s);
4983 return;
4984 }
4985
4986 if (sz == 3) {
4987 tcg_val = cpu_reg(s, rm);
4988 } else {
4989 uint64_t mask;
4990 switch (sz) {
4991 case 0:
4992 mask = 0xFF;
4993 break;
4994 case 1:
4995 mask = 0xFFFF;
4996 break;
4997 case 2:
4998 mask = 0xFFFFFFFF;
4999 break;
5000 default:
5001 g_assert_not_reached();
5002 }
5003 tcg_val = new_tmp_a64(s);
5004 tcg_gen_andi_i64(tcg_val, cpu_reg(s, rm), mask);
5005 }
5006
5007 tcg_acc = cpu_reg(s, rn);
5008 tcg_bytes = tcg_const_i32(1 << sz);
5009
5010 if (crc32c) {
5011 gen_helper_crc32c_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
5012 } else {
5013 gen_helper_crc32_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
5014 }
5015
5016 tcg_temp_free_i32(tcg_bytes);
5017}
5018
4ce31af4 5019/* Data-processing (2 source)
8220e911
AG
5020 * 31 30 29 28 21 20 16 15 10 9 5 4 0
5021 * +----+---+---+-----------------+------+--------+------+------+
5022 * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd |
5023 * +----+---+---+-----------------+------+--------+------+------+
5024 */
ad7ee8a2
CF
5025static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
5026{
8220e911
AG
5027 unsigned int sf, rm, opcode, rn, rd;
5028 sf = extract32(insn, 31, 1);
5029 rm = extract32(insn, 16, 5);
5030 opcode = extract32(insn, 10, 6);
5031 rn = extract32(insn, 5, 5);
5032 rd = extract32(insn, 0, 5);
5033
5034 if (extract32(insn, 29, 1)) {
5035 unallocated_encoding(s);
5036 return;
5037 }
5038
5039 switch (opcode) {
5040 case 2: /* UDIV */
5041 handle_div(s, false, sf, rm, rn, rd);
5042 break;
5043 case 3: /* SDIV */
5044 handle_div(s, true, sf, rm, rn, rd);
5045 break;
5046 case 8: /* LSLV */
6c1adc91
AG
5047 handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
5048 break;
8220e911 5049 case 9: /* LSRV */
6c1adc91
AG
5050 handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
5051 break;
8220e911 5052 case 10: /* ASRV */
6c1adc91
AG
5053 handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
5054 break;
8220e911 5055 case 11: /* RORV */
6c1adc91
AG
5056 handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
5057 break;
b6342a9f
RH
5058 case 12: /* PACGA */
5059 if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) {
5060 goto do_unallocated;
5061 }
5062 gen_helper_pacga(cpu_reg(s, rd), cpu_env,
5063 cpu_reg(s, rn), cpu_reg_sp(s, rm));
5064 break;
8220e911
AG
5065 case 16:
5066 case 17:
5067 case 18:
5068 case 19:
5069 case 20:
5070 case 21:
5071 case 22:
5072 case 23: /* CRC32 */
130f2e7d
PM
5073 {
5074 int sz = extract32(opcode, 0, 2);
5075 bool crc32c = extract32(opcode, 2, 1);
5076 handle_crc32(s, sf, sz, crc32c, rm, rn, rd);
8220e911 5077 break;
130f2e7d 5078 }
8220e911 5079 default:
b6342a9f 5080 do_unallocated:
8220e911
AG
5081 unallocated_encoding(s);
5082 break;
5083 }
ad7ee8a2
CF
5084}
5085
4ce31af4 5086/* Data processing - register */
ad7ee8a2
CF
5087static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
5088{
5089 switch (extract32(insn, 24, 5)) {
5090 case 0x0a: /* Logical (shifted register) */
5091 disas_logic_reg(s, insn);
5092 break;
5093 case 0x0b: /* Add/subtract */
5094 if (insn & (1 << 21)) { /* (extended register) */
5095 disas_add_sub_ext_reg(s, insn);
5096 } else {
5097 disas_add_sub_reg(s, insn);
5098 }
5099 break;
5100 case 0x1b: /* Data-processing (3 source) */
5101 disas_data_proc_3src(s, insn);
5102 break;
5103 case 0x1a:
5104 switch (extract32(insn, 21, 3)) {
5105 case 0x0: /* Add/subtract (with carry) */
5106 disas_adc_sbc(s, insn);
5107 break;
5108 case 0x2: /* Conditional compare */
750813cf 5109 disas_cc(s, insn); /* both imm and reg forms */
ad7ee8a2
CF
5110 break;
5111 case 0x4: /* Conditional select */
5112 disas_cond_select(s, insn);
5113 break;
5114 case 0x6: /* Data-processing */
5115 if (insn & (1 << 30)) { /* (1 source) */
5116 disas_data_proc_1src(s, insn);
5117 } else { /* (2 source) */
5118 disas_data_proc_2src(s, insn);
5119 }
5120 break;
5121 default:
5122 unallocated_encoding(s);
5123 break;
5124 }
5125 break;
5126 default:
5127 unallocated_encoding(s);
5128 break;
5129 }
5130}
5131
7a192925 5132static void handle_fp_compare(DisasContext *s, int size,
da7dafe7
CF
5133 unsigned int rn, unsigned int rm,
5134 bool cmp_with_zero, bool signal_all_nans)
5135{
5136 TCGv_i64 tcg_flags = tcg_temp_new_i64();
7a192925 5137 TCGv_ptr fpst = get_fpstatus_ptr(size == MO_16);
da7dafe7 5138
7a192925 5139 if (size == MO_64) {
da7dafe7
CF
5140 TCGv_i64 tcg_vn, tcg_vm;
5141
5142 tcg_vn = read_fp_dreg(s, rn);
5143 if (cmp_with_zero) {
5144 tcg_vm = tcg_const_i64(0);
5145 } else {
5146 tcg_vm = read_fp_dreg(s, rm);
5147 }
5148 if (signal_all_nans) {
5149 gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5150 } else {
5151 gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5152 }
5153 tcg_temp_free_i64(tcg_vn);
5154 tcg_temp_free_i64(tcg_vm);
5155 } else {
7a192925
AB
5156 TCGv_i32 tcg_vn = tcg_temp_new_i32();
5157 TCGv_i32 tcg_vm = tcg_temp_new_i32();
da7dafe7 5158
7a192925 5159 read_vec_element_i32(s, tcg_vn, rn, 0, size);
da7dafe7 5160 if (cmp_with_zero) {
7a192925 5161 tcg_gen_movi_i32(tcg_vm, 0);
da7dafe7 5162 } else {
7a192925 5163 read_vec_element_i32(s, tcg_vm, rm, 0, size);
da7dafe7 5164 }
7a192925
AB
5165
5166 switch (size) {
5167 case MO_32:
5168 if (signal_all_nans) {
5169 gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5170 } else {
5171 gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5172 }
5173 break;
5174 case MO_16:
5175 if (signal_all_nans) {
5176 gen_helper_vfp_cmpeh_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5177 } else {
5178 gen_helper_vfp_cmph_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5179 }
5180 break;
5181 default:
5182 g_assert_not_reached();
da7dafe7 5183 }
7a192925 5184
da7dafe7
CF
5185 tcg_temp_free_i32(tcg_vn);
5186 tcg_temp_free_i32(tcg_vm);
5187 }
5188
5189 tcg_temp_free_ptr(fpst);
5190
5191 gen_set_nzcv(tcg_flags);
5192
5193 tcg_temp_free_i64(tcg_flags);
5194}
5195
4ce31af4 5196/* Floating point compare
faa0ba46
PM
5197 * 31 30 29 28 24 23 22 21 20 16 15 14 13 10 9 5 4 0
5198 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
5199 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | op | 1 0 0 0 | Rn | op2 |
5200 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
5201 */
5202static void disas_fp_compare(DisasContext *s, uint32_t insn)
5203{
da7dafe7 5204 unsigned int mos, type, rm, op, rn, opc, op2r;
7a192925 5205 int size;
da7dafe7
CF
5206
5207 mos = extract32(insn, 29, 3);
7a192925 5208 type = extract32(insn, 22, 2);
da7dafe7
CF
5209 rm = extract32(insn, 16, 5);
5210 op = extract32(insn, 14, 2);
5211 rn = extract32(insn, 5, 5);
5212 opc = extract32(insn, 3, 2);
5213 op2r = extract32(insn, 0, 3);
5214
7a192925
AB
5215 if (mos || op || op2r) {
5216 unallocated_encoding(s);
5217 return;
5218 }
5219
5220 switch (type) {
5221 case 0:
5222 size = MO_32;
5223 break;
5224 case 1:
5225 size = MO_64;
5226 break;
5227 case 3:
5228 size = MO_16;
5763190f 5229 if (dc_isar_feature(aa64_fp16, s)) {
7a192925
AB
5230 break;
5231 }
5232 /* fallthru */
5233 default:
da7dafe7
CF
5234 unallocated_encoding(s);
5235 return;
5236 }
5237
8c6afa6a
PM
5238 if (!fp_access_check(s)) {
5239 return;
5240 }
5241
7a192925 5242 handle_fp_compare(s, size, rn, rm, opc & 1, opc & 2);
faa0ba46
PM
5243}
5244
4ce31af4 5245/* Floating point conditional compare
faa0ba46
PM
5246 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
5247 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
5248 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 0 1 | Rn | op | nzcv |
5249 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
5250 */
5251static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
5252{
513f1d76
CF
5253 unsigned int mos, type, rm, cond, rn, op, nzcv;
5254 TCGv_i64 tcg_flags;
42a268c2 5255 TCGLabel *label_continue = NULL;
7a192925 5256 int size;
513f1d76
CF
5257
5258 mos = extract32(insn, 29, 3);
7a192925 5259 type = extract32(insn, 22, 2);
513f1d76
CF
5260 rm = extract32(insn, 16, 5);
5261 cond = extract32(insn, 12, 4);
5262 rn = extract32(insn, 5, 5);
5263 op = extract32(insn, 4, 1);
5264 nzcv = extract32(insn, 0, 4);
5265
7a192925
AB
5266 if (mos) {
5267 unallocated_encoding(s);
5268 return;
5269 }
5270
5271 switch (type) {
5272 case 0:
5273 size = MO_32;
5274 break;
5275 case 1:
5276 size = MO_64;
5277 break;
5278 case 3:
5279 size = MO_16;
5763190f 5280 if (dc_isar_feature(aa64_fp16, s)) {
7a192925
AB
5281 break;
5282 }
5283 /* fallthru */
5284 default:
513f1d76
CF
5285 unallocated_encoding(s);
5286 return;
5287 }
5288
8c6afa6a
PM
5289 if (!fp_access_check(s)) {
5290 return;
5291 }
5292
513f1d76 5293 if (cond < 0x0e) { /* not always */
42a268c2 5294 TCGLabel *label_match = gen_new_label();
513f1d76
CF
5295 label_continue = gen_new_label();
5296 arm_gen_test_cc(cond, label_match);
5297 /* nomatch: */
5298 tcg_flags = tcg_const_i64(nzcv << 28);
5299 gen_set_nzcv(tcg_flags);
5300 tcg_temp_free_i64(tcg_flags);
5301 tcg_gen_br(label_continue);
5302 gen_set_label(label_match);
5303 }
5304
7a192925 5305 handle_fp_compare(s, size, rn, rm, false, op);
513f1d76
CF
5306
5307 if (cond < 0x0e) {
5308 gen_set_label(label_continue);
5309 }
faa0ba46
PM
5310}
5311
4ce31af4 5312/* Floating point conditional select
faa0ba46
PM
5313 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
5314 * +---+---+---+-----------+------+---+------+------+-----+------+------+
5315 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 1 1 | Rn | Rd |
5316 * +---+---+---+-----------+------+---+------+------+-----+------+------+
5317 */
5318static void disas_fp_csel(DisasContext *s, uint32_t insn)
5319{
5640ff62 5320 unsigned int mos, type, rm, cond, rn, rd;
6e061029
RH
5321 TCGv_i64 t_true, t_false, t_zero;
5322 DisasCompare64 c;
ace97fee 5323 TCGMemOp sz;
5640ff62
CF
5324
5325 mos = extract32(insn, 29, 3);
ace97fee 5326 type = extract32(insn, 22, 2);
5640ff62
CF
5327 rm = extract32(insn, 16, 5);
5328 cond = extract32(insn, 12, 4);
5329 rn = extract32(insn, 5, 5);
5330 rd = extract32(insn, 0, 5);
5331
ace97fee
AB
5332 if (mos) {
5333 unallocated_encoding(s);
5334 return;
5335 }
5336
5337 switch (type) {
5338 case 0:
5339 sz = MO_32;
5340 break;
5341 case 1:
5342 sz = MO_64;
5343 break;
5344 case 3:
5345 sz = MO_16;
5763190f 5346 if (dc_isar_feature(aa64_fp16, s)) {
ace97fee
AB
5347 break;
5348 }
5349 /* fallthru */
5350 default:
5640ff62
CF
5351 unallocated_encoding(s);
5352 return;
5353 }
5354
8c6afa6a
PM
5355 if (!fp_access_check(s)) {
5356 return;
5357 }
5358
ace97fee 5359 /* Zero extend sreg & hreg inputs to 64 bits now. */
6e061029
RH
5360 t_true = tcg_temp_new_i64();
5361 t_false = tcg_temp_new_i64();
ace97fee
AB
5362 read_vec_element(s, t_true, rn, 0, sz);
5363 read_vec_element(s, t_false, rm, 0, sz);
5640ff62 5364
6e061029
RH
5365 a64_test_cc(&c, cond);
5366 t_zero = tcg_const_i64(0);
5367 tcg_gen_movcond_i64(c.cond, t_true, c.value, t_zero, t_true, t_false);
5368 tcg_temp_free_i64(t_zero);
5369 tcg_temp_free_i64(t_false);
5370 a64_free_cc(&c);
5640ff62 5371
ace97fee 5372 /* Note that sregs & hregs write back zeros to the high bits,
6e061029
RH
5373 and we've already done the zero-extension. */
5374 write_fp_dreg(s, rd, t_true);
5375 tcg_temp_free_i64(t_true);
faa0ba46
PM
5376}
5377
c2c08713
AB
5378/* Floating-point data-processing (1 source) - half precision */
5379static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
5380{
5381 TCGv_ptr fpst = NULL;
3d99d931 5382 TCGv_i32 tcg_op = read_fp_hreg(s, rn);
c2c08713
AB
5383 TCGv_i32 tcg_res = tcg_temp_new_i32();
5384
c2c08713
AB
5385 switch (opcode) {
5386 case 0x0: /* FMOV */
5387 tcg_gen_mov_i32(tcg_res, tcg_op);
5388 break;
5389 case 0x1: /* FABS */
5390 tcg_gen_andi_i32(tcg_res, tcg_op, 0x7fff);
5391 break;
5392 case 0x2: /* FNEG */
5393 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
5394 break;
5395 case 0x3: /* FSQRT */
905edee9
AB
5396 fpst = get_fpstatus_ptr(true);
5397 gen_helper_sqrt_f16(tcg_res, tcg_op, fpst);
c2c08713
AB
5398 break;
5399 case 0x8: /* FRINTN */
5400 case 0x9: /* FRINTP */
5401 case 0xa: /* FRINTM */
5402 case 0xb: /* FRINTZ */
5403 case 0xc: /* FRINTA */
5404 {
5405 TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
5406 fpst = get_fpstatus_ptr(true);
5407
5408 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
5409 gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
5410
5411 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
5412 tcg_temp_free_i32(tcg_rmode);
5413 break;
5414 }
5415 case 0xe: /* FRINTX */
5416 fpst = get_fpstatus_ptr(true);
5417 gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, fpst);
5418 break;
5419 case 0xf: /* FRINTI */
5420 fpst = get_fpstatus_ptr(true);
5421 gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
5422 break;
5423 default:
5424 abort();
5425 }
5426
5427 write_fp_sreg(s, rd, tcg_res);
5428
5429 if (fpst) {
5430 tcg_temp_free_ptr(fpst);
5431 }
5432 tcg_temp_free_i32(tcg_op);
5433 tcg_temp_free_i32(tcg_res);
5434}
5435
4ce31af4 5436/* Floating-point data-processing (1 source) - single precision */
d9b0848d
PM
5437static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
5438{
5439 TCGv_ptr fpst;
5440 TCGv_i32 tcg_op;
5441 TCGv_i32 tcg_res;
5442
d81ce0ef 5443 fpst = get_fpstatus_ptr(false);
d9b0848d
PM
5444 tcg_op = read_fp_sreg(s, rn);
5445 tcg_res = tcg_temp_new_i32();
5446
5447 switch (opcode) {
5448 case 0x0: /* FMOV */
5449 tcg_gen_mov_i32(tcg_res, tcg_op);
5450 break;
5451 case 0x1: /* FABS */
5452 gen_helper_vfp_abss(tcg_res, tcg_op);
5453 break;
5454 case 0x2: /* FNEG */
5455 gen_helper_vfp_negs(tcg_res, tcg_op);
5456 break;
5457 case 0x3: /* FSQRT */
5458 gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
5459 break;
5460 case 0x8: /* FRINTN */
5461 case 0x9: /* FRINTP */
5462 case 0xa: /* FRINTM */
5463 case 0xb: /* FRINTZ */
5464 case 0xc: /* FRINTA */
5465 {
5466 TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
5467
9b049916 5468 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
d9b0848d
PM
5469 gen_helper_rints(tcg_res, tcg_op, fpst);
5470
9b049916 5471 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
d9b0848d
PM
5472 tcg_temp_free_i32(tcg_rmode);
5473 break;
5474 }
5475 case 0xe: /* FRINTX */
5476 gen_helper_rints_exact(tcg_res, tcg_op, fpst);
5477 break;
5478 case 0xf: /* FRINTI */
5479 gen_helper_rints(tcg_res, tcg_op, fpst);
5480 break;
5481 default:
5482 abort();
5483 }
5484
5485 write_fp_sreg(s, rd, tcg_res);
5486
5487 tcg_temp_free_ptr(fpst);
5488 tcg_temp_free_i32(tcg_op);
5489 tcg_temp_free_i32(tcg_res);
5490}
5491
4ce31af4 5492/* Floating-point data-processing (1 source) - double precision */
d9b0848d
PM
5493static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
5494{
5495 TCGv_ptr fpst;
5496 TCGv_i64 tcg_op;
5497 TCGv_i64 tcg_res;
5498
377ef731
RH
5499 switch (opcode) {
5500 case 0x0: /* FMOV */
5501 gen_gvec_fn2(s, false, rd, rn, tcg_gen_gvec_mov, 0);
5502 return;
5503 }
5504
d81ce0ef 5505 fpst = get_fpstatus_ptr(false);
d9b0848d
PM
5506 tcg_op = read_fp_dreg(s, rn);
5507 tcg_res = tcg_temp_new_i64();
5508
5509 switch (opcode) {
d9b0848d
PM
5510 case 0x1: /* FABS */
5511 gen_helper_vfp_absd(tcg_res, tcg_op);
5512 break;
5513 case 0x2: /* FNEG */
5514 gen_helper_vfp_negd(tcg_res, tcg_op);
5515 break;
5516 case 0x3: /* FSQRT */
5517 gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
5518 break;
5519 case 0x8: /* FRINTN */
5520 case 0x9: /* FRINTP */
5521 case 0xa: /* FRINTM */
5522 case 0xb: /* FRINTZ */
5523 case 0xc: /* FRINTA */
5524 {
5525 TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
5526
9b049916 5527 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
d9b0848d
PM
5528 gen_helper_rintd(tcg_res, tcg_op, fpst);
5529
9b049916 5530 gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
d9b0848d
PM
5531 tcg_temp_free_i32(tcg_rmode);
5532 break;
5533 }
5534 case 0xe: /* FRINTX */
5535 gen_helper_rintd_exact(tcg_res, tcg_op, fpst);
5536 break;
5537 case 0xf: /* FRINTI */
5538 gen_helper_rintd(tcg_res, tcg_op, fpst);
5539 break;
5540 default:
5541 abort();
5542 }
5543
5544 write_fp_dreg(s, rd, tcg_res);
5545
5546 tcg_temp_free_ptr(fpst);
5547 tcg_temp_free_i64(tcg_op);
5548 tcg_temp_free_i64(tcg_res);
5549}
5550
8900aad2
PM
5551static void handle_fp_fcvt(DisasContext *s, int opcode,
5552 int rd, int rn, int dtype, int ntype)
5553{
5554 switch (ntype) {
5555 case 0x0:
5556 {
5557 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
5558 if (dtype == 1) {
5559 /* Single to double */
5560 TCGv_i64 tcg_rd = tcg_temp_new_i64();
5561 gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, cpu_env);
5562 write_fp_dreg(s, rd, tcg_rd);
5563 tcg_temp_free_i64(tcg_rd);
5564 } else {
5565 /* Single to half */
5566 TCGv_i32 tcg_rd = tcg_temp_new_i32();
486624fc
AB
5567 TCGv_i32 ahp = get_ahp_flag();
5568 TCGv_ptr fpst = get_fpstatus_ptr(false);
5569
5570 gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp);
8900aad2
PM
5571 /* write_fp_sreg is OK here because top half of tcg_rd is zero */
5572 write_fp_sreg(s, rd, tcg_rd);
5573 tcg_temp_free_i32(tcg_rd);
486624fc
AB
5574 tcg_temp_free_i32(ahp);
5575 tcg_temp_free_ptr(fpst);
8900aad2
PM
5576 }
5577 tcg_temp_free_i32(tcg_rn);
5578 break;
5579 }
5580 case 0x1:
5581 {
5582 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
5583 TCGv_i32 tcg_rd = tcg_temp_new_i32();
5584 if (dtype == 0) {
5585 /* Double to single */
5586 gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
5587 } else {
486624fc
AB
5588 TCGv_ptr fpst = get_fpstatus_ptr(false);
5589 TCGv_i32 ahp = get_ahp_flag();
8900aad2 5590 /* Double to half */
486624fc 5591 gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
8900aad2 5592 /* write_fp_sreg is OK here because top half of tcg_rd is zero */
486624fc
AB
5593 tcg_temp_free_ptr(fpst);
5594 tcg_temp_free_i32(ahp);
8900aad2
PM
5595 }
5596 write_fp_sreg(s, rd, tcg_rd);
5597 tcg_temp_free_i32(tcg_rd);
5598 tcg_temp_free_i64(tcg_rn);
5599 break;
5600 }
5601 case 0x3:
5602 {
5603 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
486624fc
AB
5604 TCGv_ptr tcg_fpst = get_fpstatus_ptr(false);
5605 TCGv_i32 tcg_ahp = get_ahp_flag();
8900aad2
PM
5606 tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
5607 if (dtype == 0) {
5608 /* Half to single */
5609 TCGv_i32 tcg_rd = tcg_temp_new_i32();
486624fc 5610 gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
8900aad2 5611 write_fp_sreg(s, rd, tcg_rd);
486624fc
AB
5612 tcg_temp_free_ptr(tcg_fpst);
5613 tcg_temp_free_i32(tcg_ahp);
8900aad2
PM
5614 tcg_temp_free_i32(tcg_rd);
5615 } else {
5616 /* Half to double */
5617 TCGv_i64 tcg_rd = tcg_temp_new_i64();
486624fc 5618 gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
8900aad2
PM
5619 write_fp_dreg(s, rd, tcg_rd);
5620 tcg_temp_free_i64(tcg_rd);
5621 }
5622 tcg_temp_free_i32(tcg_rn);
5623 break;
5624 }
5625 default:
5626 abort();
5627 }
5628}
5629
4ce31af4 5630/* Floating point data-processing (1 source)
faa0ba46
PM
5631 * 31 30 29 28 24 23 22 21 20 15 14 10 9 5 4 0
5632 * +---+---+---+-----------+------+---+--------+-----------+------+------+
5633 * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd |
5634 * +---+---+---+-----------+------+---+--------+-----------+------+------+
5635 */
5636static void disas_fp_1src(DisasContext *s, uint32_t insn)
5637{
d9b0848d
PM
5638 int type = extract32(insn, 22, 2);
5639 int opcode = extract32(insn, 15, 6);
5640 int rn = extract32(insn, 5, 5);
5641 int rd = extract32(insn, 0, 5);
5642
5643 switch (opcode) {
5644 case 0x4: case 0x5: case 0x7:
8900aad2 5645 {
d9b0848d 5646 /* FCVT between half, single and double precision */
8900aad2
PM
5647 int dtype = extract32(opcode, 0, 2);
5648 if (type == 2 || dtype == type) {
5649 unallocated_encoding(s);
5650 return;
5651 }
8c6afa6a
PM
5652 if (!fp_access_check(s)) {
5653 return;
5654 }
5655
8900aad2 5656 handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
d9b0848d 5657 break;
8900aad2 5658 }
d9b0848d
PM
5659 case 0x0 ... 0x3:
5660 case 0x8 ... 0xc:
5661 case 0xe ... 0xf:
5662 /* 32-to-32 and 64-to-64 ops */
5663 switch (type) {
5664 case 0:
8c6afa6a
PM
5665 if (!fp_access_check(s)) {
5666 return;
5667 }
5668
d9b0848d
PM
5669 handle_fp_1src_single(s, opcode, rd, rn);
5670 break;
5671 case 1:
8c6afa6a
PM
5672 if (!fp_access_check(s)) {
5673 return;
5674 }
5675
d9b0848d
PM
5676 handle_fp_1src_double(s, opcode, rd, rn);
5677 break;
c2c08713 5678 case 3:
5763190f 5679 if (!dc_isar_feature(aa64_fp16, s)) {
c2c08713
AB
5680 unallocated_encoding(s);
5681 return;
5682 }
5683
5684 if (!fp_access_check(s)) {
5685 return;
5686 }
5687
5688 handle_fp_1src_half(s, opcode, rd, rn);
5689 break;
d9b0848d
PM
5690 default:
5691 unallocated_encoding(s);
5692 }
5693 break;
5694 default:
5695 unallocated_encoding(s);
5696 break;
5697 }
faa0ba46
PM
5698}
5699
4ce31af4 5700/* Floating-point data-processing (2 source) - single precision */
ec73d2e0
AG
5701static void handle_fp_2src_single(DisasContext *s, int opcode,
5702 int rd, int rn, int rm)
5703{
5704 TCGv_i32 tcg_op1;
5705 TCGv_i32 tcg_op2;
5706 TCGv_i32 tcg_res;
5707 TCGv_ptr fpst;
5708
5709 tcg_res = tcg_temp_new_i32();
d81ce0ef 5710 fpst = get_fpstatus_ptr(false);
ec73d2e0
AG
5711 tcg_op1 = read_fp_sreg(s, rn);
5712 tcg_op2 = read_fp_sreg(s, rm);
5713
5714 switch (opcode) {
5715 case 0x0: /* FMUL */
5716 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
5717 break;
5718 case 0x1: /* FDIV */
5719 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
5720 break;
5721 case 0x2: /* FADD */
5722 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
5723 break;
5724 case 0x3: /* FSUB */
5725 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
5726 break;
5727 case 0x4: /* FMAX */
5728 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
5729 break;
5730 case 0x5: /* FMIN */
5731 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
5732 break;
5733 case 0x6: /* FMAXNM */
5734 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
5735 break;
5736 case 0x7: /* FMINNM */
5737 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
5738 break;
5739 case 0x8: /* FNMUL */
5740 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
5741 gen_helper_vfp_negs(tcg_res, tcg_res);
5742 break;
5743 }
5744
5745 write_fp_sreg(s, rd, tcg_res);
5746
5747 tcg_temp_free_ptr(fpst);
5748 tcg_temp_free_i32(tcg_op1);
5749 tcg_temp_free_i32(tcg_op2);
5750 tcg_temp_free_i32(tcg_res);
5751}
5752
4ce31af4 5753/* Floating-point data-processing (2 source) - double precision */
ec73d2e0
AG
5754static void handle_fp_2src_double(DisasContext *s, int opcode,
5755 int rd, int rn, int rm)
5756{
5757 TCGv_i64 tcg_op1;
5758 TCGv_i64 tcg_op2;
5759 TCGv_i64 tcg_res;
5760 TCGv_ptr fpst;
5761
5762 tcg_res = tcg_temp_new_i64();
d81ce0ef 5763 fpst = get_fpstatus_ptr(false);
ec73d2e0
AG
5764 tcg_op1 = read_fp_dreg(s, rn);
5765 tcg_op2 = read_fp_dreg(s, rm);
5766
5767 switch (opcode) {
5768 case 0x0: /* FMUL */
5769 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
5770 break;
5771 case 0x1: /* FDIV */
5772 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
5773 break;
5774 case 0x2: /* FADD */
5775 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
5776 break;
5777 case 0x3: /* FSUB */
5778 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
5779 break;
5780 case 0x4: /* FMAX */
5781 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
5782 break;
5783 case 0x5: /* FMIN */
5784 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
5785 break;
5786 case 0x6: /* FMAXNM */
5787 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5788 break;
5789 case 0x7: /* FMINNM */
5790 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5791 break;
5792 case 0x8: /* FNMUL */
5793 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
5794 gen_helper_vfp_negd(tcg_res, tcg_res);
5795 break;
5796 }
5797
5798 write_fp_dreg(s, rd, tcg_res);
5799
5800 tcg_temp_free_ptr(fpst);
5801 tcg_temp_free_i64(tcg_op1);
5802 tcg_temp_free_i64(tcg_op2);
5803 tcg_temp_free_i64(tcg_res);
5804}
5805
b8f5171c
RH
5806/* Floating-point data-processing (2 source) - half precision */
5807static void handle_fp_2src_half(DisasContext *s, int opcode,
5808 int rd, int rn, int rm)
5809{
5810 TCGv_i32 tcg_op1;
5811 TCGv_i32 tcg_op2;
5812 TCGv_i32 tcg_res;
5813 TCGv_ptr fpst;
5814
5815 tcg_res = tcg_temp_new_i32();
5816 fpst = get_fpstatus_ptr(true);
5817 tcg_op1 = read_fp_hreg(s, rn);
5818 tcg_op2 = read_fp_hreg(s, rm);
5819
5820 switch (opcode) {
5821 case 0x0: /* FMUL */
5822 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
5823 break;
5824 case 0x1: /* FDIV */
5825 gen_helper_advsimd_divh(tcg_res, tcg_op1, tcg_op2, fpst);
5826 break;
5827 case 0x2: /* FADD */
5828 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
5829 break;
5830 case 0x3: /* FSUB */
5831 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
5832 break;
5833 case 0x4: /* FMAX */
5834 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
5835 break;
5836 case 0x5: /* FMIN */
5837 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
5838 break;
5839 case 0x6: /* FMAXNM */
5840 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
5841 break;
5842 case 0x7: /* FMINNM */
5843 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
5844 break;
5845 case 0x8: /* FNMUL */
5846 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
5847 tcg_gen_xori_i32(tcg_res, tcg_res, 0x8000);
5848 break;
5849 default:
5850 g_assert_not_reached();
5851 }
5852
5853 write_fp_sreg(s, rd, tcg_res);
5854
5855 tcg_temp_free_ptr(fpst);
5856 tcg_temp_free_i32(tcg_op1);
5857 tcg_temp_free_i32(tcg_op2);
5858 tcg_temp_free_i32(tcg_res);
5859}
5860
4ce31af4 5861/* Floating point data-processing (2 source)
faa0ba46
PM
5862 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
5863 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
5864 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | opcode | 1 0 | Rn | Rd |
5865 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
5866 */
5867static void disas_fp_2src(DisasContext *s, uint32_t insn)
5868{
ec73d2e0
AG
5869 int type = extract32(insn, 22, 2);
5870 int rd = extract32(insn, 0, 5);
5871 int rn = extract32(insn, 5, 5);
5872 int rm = extract32(insn, 16, 5);
5873 int opcode = extract32(insn, 12, 4);
5874
5875 if (opcode > 8) {
5876 unallocated_encoding(s);
5877 return;
5878 }
5879
5880 switch (type) {
5881 case 0:
8c6afa6a
PM
5882 if (!fp_access_check(s)) {
5883 return;
5884 }
ec73d2e0
AG
5885 handle_fp_2src_single(s, opcode, rd, rn, rm);
5886 break;
5887 case 1:
8c6afa6a
PM
5888 if (!fp_access_check(s)) {
5889 return;
5890 }
ec73d2e0
AG
5891 handle_fp_2src_double(s, opcode, rd, rn, rm);
5892 break;
b8f5171c 5893 case 3:
5763190f 5894 if (!dc_isar_feature(aa64_fp16, s)) {
b8f5171c
RH
5895 unallocated_encoding(s);
5896 return;
5897 }
5898 if (!fp_access_check(s)) {
5899 return;
5900 }
5901 handle_fp_2src_half(s, opcode, rd, rn, rm);
5902 break;
ec73d2e0
AG
5903 default:
5904 unallocated_encoding(s);
5905 }
faa0ba46
PM
5906}
5907
4ce31af4 5908/* Floating-point data-processing (3 source) - single precision */
6a30667f
AG
5909static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
5910 int rd, int rn, int rm, int ra)
5911{
5912 TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
5913 TCGv_i32 tcg_res = tcg_temp_new_i32();
d81ce0ef 5914 TCGv_ptr fpst = get_fpstatus_ptr(false);
6a30667f
AG
5915
5916 tcg_op1 = read_fp_sreg(s, rn);
5917 tcg_op2 = read_fp_sreg(s, rm);
5918 tcg_op3 = read_fp_sreg(s, ra);
5919
5920 /* These are fused multiply-add, and must be done as one
5921 * floating point operation with no rounding between the
5922 * multiplication and addition steps.
5923 * NB that doing the negations here as separate steps is
5924 * correct : an input NaN should come out with its sign bit
5925 * flipped if it is a negated-input.
5926 */
5927 if (o1 == true) {
5928 gen_helper_vfp_negs(tcg_op3, tcg_op3);
5929 }
5930
5931 if (o0 != o1) {
5932 gen_helper_vfp_negs(tcg_op1, tcg_op1);
5933 }
5934
5935 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
5936
5937 write_fp_sreg(s, rd, tcg_res);
5938
5939 tcg_temp_free_ptr(fpst);
5940 tcg_temp_free_i32(tcg_op1);
5941 tcg_temp_free_i32(tcg_op2);
5942 tcg_temp_free_i32(tcg_op3);
5943 tcg_temp_free_i32(tcg_res);
5944}
5945
4ce31af4 5946/* Floating-point data-processing (3 source) - double precision */
6a30667f
AG
5947static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
5948 int rd, int rn, int rm, int ra)
5949{
5950 TCGv_i64 tcg_op1, tcg_op2, tcg_op3;
5951 TCGv_i64 tcg_res = tcg_temp_new_i64();
d81ce0ef 5952 TCGv_ptr fpst = get_fpstatus_ptr(false);
6a30667f
AG
5953
5954 tcg_op1 = read_fp_dreg(s, rn);
5955 tcg_op2 = read_fp_dreg(s, rm);
5956 tcg_op3 = read_fp_dreg(s, ra);
5957
5958 /* These are fused multiply-add, and must be done as one
5959 * floating point operation with no rounding between the
5960 * multiplication and addition steps.
5961 * NB that doing the negations here as separate steps is
5962 * correct : an input NaN should come out with its sign bit
5963 * flipped if it is a negated-input.
5964 */
5965 if (o1 == true) {
5966 gen_helper_vfp_negd(tcg_op3, tcg_op3);
5967 }
5968
5969 if (o0 != o1) {
5970 gen_helper_vfp_negd(tcg_op1, tcg_op1);
5971 }
5972
5973 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
5974
5975 write_fp_dreg(s, rd, tcg_res);
5976
5977 tcg_temp_free_ptr(fpst);
5978 tcg_temp_free_i64(tcg_op1);
5979 tcg_temp_free_i64(tcg_op2);
5980 tcg_temp_free_i64(tcg_op3);
5981 tcg_temp_free_i64(tcg_res);
5982}
5983
95f9864f
RH
5984/* Floating-point data-processing (3 source) - half precision */
5985static void handle_fp_3src_half(DisasContext *s, bool o0, bool o1,
5986 int rd, int rn, int rm, int ra)
5987{
5988 TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
5989 TCGv_i32 tcg_res = tcg_temp_new_i32();
5990 TCGv_ptr fpst = get_fpstatus_ptr(true);
5991
5992 tcg_op1 = read_fp_hreg(s, rn);
5993 tcg_op2 = read_fp_hreg(s, rm);
5994 tcg_op3 = read_fp_hreg(s, ra);
5995
5996 /* These are fused multiply-add, and must be done as one
5997 * floating point operation with no rounding between the
5998 * multiplication and addition steps.
5999 * NB that doing the negations here as separate steps is
6000 * correct : an input NaN should come out with its sign bit
6001 * flipped if it is a negated-input.
6002 */
6003 if (o1 == true) {
6004 tcg_gen_xori_i32(tcg_op3, tcg_op3, 0x8000);
6005 }
6006
6007 if (o0 != o1) {
6008 tcg_gen_xori_i32(tcg_op1, tcg_op1, 0x8000);
6009 }
6010
6011 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
6012
6013 write_fp_sreg(s, rd, tcg_res);
6014
6015 tcg_temp_free_ptr(fpst);
6016 tcg_temp_free_i32(tcg_op1);
6017 tcg_temp_free_i32(tcg_op2);
6018 tcg_temp_free_i32(tcg_op3);
6019 tcg_temp_free_i32(tcg_res);
6020}
6021
4ce31af4 6022/* Floating point data-processing (3 source)
faa0ba46
PM
6023 * 31 30 29 28 24 23 22 21 20 16 15 14 10 9 5 4 0
6024 * +---+---+---+-----------+------+----+------+----+------+------+------+
6025 * | M | 0 | S | 1 1 1 1 1 | type | o1 | Rm | o0 | Ra | Rn | Rd |
6026 * +---+---+---+-----------+------+----+------+----+------+------+------+
6027 */
6028static void disas_fp_3src(DisasContext *s, uint32_t insn)
6029{
6a30667f
AG
6030 int type = extract32(insn, 22, 2);
6031 int rd = extract32(insn, 0, 5);
6032 int rn = extract32(insn, 5, 5);
6033 int ra = extract32(insn, 10, 5);
6034 int rm = extract32(insn, 16, 5);
6035 bool o0 = extract32(insn, 15, 1);
6036 bool o1 = extract32(insn, 21, 1);
6037
6038 switch (type) {
6039 case 0:
8c6afa6a
PM
6040 if (!fp_access_check(s)) {
6041 return;
6042 }
6a30667f
AG
6043 handle_fp_3src_single(s, o0, o1, rd, rn, rm, ra);
6044 break;
6045 case 1:
8c6afa6a
PM
6046 if (!fp_access_check(s)) {
6047 return;
6048 }
6a30667f
AG
6049 handle_fp_3src_double(s, o0, o1, rd, rn, rm, ra);
6050 break;
95f9864f 6051 case 3:
5763190f 6052 if (!dc_isar_feature(aa64_fp16, s)) {
95f9864f
RH
6053 unallocated_encoding(s);
6054 return;
6055 }
6056 if (!fp_access_check(s)) {
6057 return;
6058 }
6059 handle_fp_3src_half(s, o0, o1, rd, rn, rm, ra);
6060 break;
6a30667f
AG
6061 default:
6062 unallocated_encoding(s);
6063 }
faa0ba46
PM
6064}
6065
e90a99fe
RH
6066/* The imm8 encodes the sign bit, enough bits to represent an exponent in
6067 * the range 01....1xx to 10....0xx, and the most significant 4 bits of
6068 * the mantissa; see VFPExpandImm() in the v8 ARM ARM.
6069 */
8c71baed 6070uint64_t vfp_expand_imm(int size, uint8_t imm8)
e90a99fe
RH
6071{
6072 uint64_t imm;
6073
6074 switch (size) {
6075 case MO_64:
6076 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
6077 (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
6078 extract32(imm8, 0, 6);
6079 imm <<= 48;
6080 break;
6081 case MO_32:
6082 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
6083 (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
6084 (extract32(imm8, 0, 6) << 3);
6085 imm <<= 16;
6086 break;
8081796a
RH
6087 case MO_16:
6088 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
6089 (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) |
6090 (extract32(imm8, 0, 6) << 6);
6091 break;
e90a99fe
RH
6092 default:
6093 g_assert_not_reached();
6094 }
6095 return imm;
6096}
6097
4ce31af4 6098/* Floating point immediate
faa0ba46
PM
6099 * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
6100 * +---+---+---+-----------+------+---+------------+-------+------+------+
6101 * | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd |
6102 * +---+---+---+-----------+------+---+------------+-------+------+------+
6103 */
6104static void disas_fp_imm(DisasContext *s, uint32_t insn)
6105{
6163f868
AG
6106 int rd = extract32(insn, 0, 5);
6107 int imm8 = extract32(insn, 13, 8);
6ba28ddb 6108 int type = extract32(insn, 22, 2);
6163f868
AG
6109 uint64_t imm;
6110 TCGv_i64 tcg_res;
6ba28ddb 6111 TCGMemOp sz;
6163f868 6112
6ba28ddb
AB
6113 switch (type) {
6114 case 0:
6115 sz = MO_32;
6116 break;
6117 case 1:
6118 sz = MO_64;
6119 break;
6120 case 3:
6121 sz = MO_16;
5763190f 6122 if (dc_isar_feature(aa64_fp16, s)) {
6ba28ddb
AB
6123 break;
6124 }
6125 /* fallthru */
6126 default:
6163f868
AG
6127 unallocated_encoding(s);
6128 return;
6129 }
6130
8c6afa6a
PM
6131 if (!fp_access_check(s)) {
6132 return;
6133 }
6134
6ba28ddb 6135 imm = vfp_expand_imm(sz, imm8);
6163f868
AG
6136
6137 tcg_res = tcg_const_i64(imm);
6138 write_fp_dreg(s, rd, tcg_res);
6139 tcg_temp_free_i64(tcg_res);
faa0ba46
PM
6140}
6141
52a1f6a3
AG
6142/* Handle floating point <=> fixed point conversions. Note that we can
6143 * also deal with fp <=> integer conversions as a special case (scale == 64)
6144 * OPTME: consider handling that special case specially or at least skipping
6145 * the call to scalbn in the helpers for zero shifts.
6146 */
6147static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
6148 bool itof, int rmode, int scale, int sf, int type)
6149{
6150 bool is_signed = !(opcode & 1);
52a1f6a3 6151 TCGv_ptr tcg_fpstatus;
564a0632
RH
6152 TCGv_i32 tcg_shift, tcg_single;
6153 TCGv_i64 tcg_double;
52a1f6a3 6154
564a0632 6155 tcg_fpstatus = get_fpstatus_ptr(type == 3);
52a1f6a3
AG
6156
6157 tcg_shift = tcg_const_i32(64 - scale);
6158
6159 if (itof) {
6160 TCGv_i64 tcg_int = cpu_reg(s, rn);
6161 if (!sf) {
6162 TCGv_i64 tcg_extend = new_tmp_a64(s);
6163
6164 if (is_signed) {
6165 tcg_gen_ext32s_i64(tcg_extend, tcg_int);
6166 } else {
6167 tcg_gen_ext32u_i64(tcg_extend, tcg_int);
6168 }
6169
6170 tcg_int = tcg_extend;
6171 }
6172
564a0632
RH
6173 switch (type) {
6174 case 1: /* float64 */
6175 tcg_double = tcg_temp_new_i64();
52a1f6a3
AG
6176 if (is_signed) {
6177 gen_helper_vfp_sqtod(tcg_double, tcg_int,
6178 tcg_shift, tcg_fpstatus);
6179 } else {
6180 gen_helper_vfp_uqtod(tcg_double, tcg_int,
6181 tcg_shift, tcg_fpstatus);
6182 }
6183 write_fp_dreg(s, rd, tcg_double);
6184 tcg_temp_free_i64(tcg_double);
564a0632
RH
6185 break;
6186
6187 case 0: /* float32 */
6188 tcg_single = tcg_temp_new_i32();
52a1f6a3
AG
6189 if (is_signed) {
6190 gen_helper_vfp_sqtos(tcg_single, tcg_int,
6191 tcg_shift, tcg_fpstatus);
6192 } else {
6193 gen_helper_vfp_uqtos(tcg_single, tcg_int,
6194 tcg_shift, tcg_fpstatus);
6195 }
6196 write_fp_sreg(s, rd, tcg_single);
6197 tcg_temp_free_i32(tcg_single);
564a0632
RH
6198 break;
6199
6200 case 3: /* float16 */
6201 tcg_single = tcg_temp_new_i32();
6202 if (is_signed) {
6203 gen_helper_vfp_sqtoh(tcg_single, tcg_int,
6204 tcg_shift, tcg_fpstatus);
6205 } else {
6206 gen_helper_vfp_uqtoh(tcg_single, tcg_int,
6207 tcg_shift, tcg_fpstatus);
6208 }
6209 write_fp_sreg(s, rd, tcg_single);
6210 tcg_temp_free_i32(tcg_single);
6211 break;
6212
6213 default:
6214 g_assert_not_reached();
52a1f6a3
AG
6215 }
6216 } else {
6217 TCGv_i64 tcg_int = cpu_reg(s, rd);
6218 TCGv_i32 tcg_rmode;
6219
6220 if (extract32(opcode, 2, 1)) {
6221 /* There are too many rounding modes to all fit into rmode,
6222 * so FCVTA[US] is a special case.
6223 */
6224 rmode = FPROUNDING_TIEAWAY;
6225 }
6226
6227 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
6228
9b049916 6229 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
52a1f6a3 6230
564a0632
RH
6231 switch (type) {
6232 case 1: /* float64 */
6233 tcg_double = read_fp_dreg(s, rn);
52a1f6a3
AG
6234 if (is_signed) {
6235 if (!sf) {
6236 gen_helper_vfp_tosld(tcg_int, tcg_double,
6237 tcg_shift, tcg_fpstatus);
6238 } else {
6239 gen_helper_vfp_tosqd(tcg_int, tcg_double,
6240 tcg_shift, tcg_fpstatus);
6241 }
6242 } else {
6243 if (!sf) {
6244 gen_helper_vfp_tould(tcg_int, tcg_double,
6245 tcg_shift, tcg_fpstatus);
6246 } else {
6247 gen_helper_vfp_touqd(tcg_int, tcg_double,
6248 tcg_shift, tcg_fpstatus);
6249 }
6250 }
564a0632
RH
6251 if (!sf) {
6252 tcg_gen_ext32u_i64(tcg_int, tcg_int);
6253 }
52a1f6a3 6254 tcg_temp_free_i64(tcg_double);
564a0632
RH
6255 break;
6256
6257 case 0: /* float32 */
6258 tcg_single = read_fp_sreg(s, rn);
52a1f6a3
AG
6259 if (sf) {
6260 if (is_signed) {
6261 gen_helper_vfp_tosqs(tcg_int, tcg_single,
6262 tcg_shift, tcg_fpstatus);
6263 } else {
6264 gen_helper_vfp_touqs(tcg_int, tcg_single,
6265 tcg_shift, tcg_fpstatus);
6266 }
6267 } else {
6268 TCGv_i32 tcg_dest = tcg_temp_new_i32();
6269 if (is_signed) {
6270 gen_helper_vfp_tosls(tcg_dest, tcg_single,
6271 tcg_shift, tcg_fpstatus);
6272 } else {
6273 gen_helper_vfp_touls(tcg_dest, tcg_single,
6274 tcg_shift, tcg_fpstatus);
6275 }
6276 tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
6277 tcg_temp_free_i32(tcg_dest);
6278 }
6279 tcg_temp_free_i32(tcg_single);
564a0632
RH
6280 break;
6281
6282 case 3: /* float16 */
6283 tcg_single = read_fp_sreg(s, rn);
6284 if (sf) {
6285 if (is_signed) {
6286 gen_helper_vfp_tosqh(tcg_int, tcg_single,
6287 tcg_shift, tcg_fpstatus);
6288 } else {
6289 gen_helper_vfp_touqh(tcg_int, tcg_single,
6290 tcg_shift, tcg_fpstatus);
6291 }
6292 } else {
6293 TCGv_i32 tcg_dest = tcg_temp_new_i32();
6294 if (is_signed) {
6295 gen_helper_vfp_toslh(tcg_dest, tcg_single,
6296 tcg_shift, tcg_fpstatus);
6297 } else {
6298 gen_helper_vfp_toulh(tcg_dest, tcg_single,
6299 tcg_shift, tcg_fpstatus);
6300 }
6301 tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
6302 tcg_temp_free_i32(tcg_dest);
6303 }
6304 tcg_temp_free_i32(tcg_single);
6305 break;
6306
6307 default:
6308 g_assert_not_reached();
52a1f6a3
AG
6309 }
6310
9b049916 6311 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
52a1f6a3 6312 tcg_temp_free_i32(tcg_rmode);
52a1f6a3
AG
6313 }
6314
6315 tcg_temp_free_ptr(tcg_fpstatus);
6316 tcg_temp_free_i32(tcg_shift);
6317}
6318
4ce31af4 6319/* Floating point <-> fixed point conversions
faa0ba46
PM
6320 * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
6321 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
6322 * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale | Rn | Rd |
6323 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
6324 */
6325static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
6326{
52a1f6a3
AG
6327 int rd = extract32(insn, 0, 5);
6328 int rn = extract32(insn, 5, 5);
6329 int scale = extract32(insn, 10, 6);
6330 int opcode = extract32(insn, 16, 3);
6331 int rmode = extract32(insn, 19, 2);
6332 int type = extract32(insn, 22, 2);
6333 bool sbit = extract32(insn, 29, 1);
6334 bool sf = extract32(insn, 31, 1);
6335 bool itof;
6336
27527280
RH
6337 if (sbit || (!sf && scale < 32)) {
6338 unallocated_encoding(s);
6339 return;
6340 }
6341
6342 switch (type) {
6343 case 0: /* float32 */
6344 case 1: /* float64 */
6345 break;
6346 case 3: /* float16 */
5763190f 6347 if (dc_isar_feature(aa64_fp16, s)) {
27527280
RH
6348 break;
6349 }
6350 /* fallthru */
6351 default:
52a1f6a3
AG
6352 unallocated_encoding(s);
6353 return;
6354 }
6355
6356 switch ((rmode << 3) | opcode) {
6357 case 0x2: /* SCVTF */
6358 case 0x3: /* UCVTF */
6359 itof = true;
6360 break;
6361 case 0x18: /* FCVTZS */
6362 case 0x19: /* FCVTZU */
6363 itof = false;
6364 break;
6365 default:
6366 unallocated_encoding(s);
6367 return;
6368 }
6369
8c6afa6a
PM
6370 if (!fp_access_check(s)) {
6371 return;
6372 }
6373
52a1f6a3 6374 handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
faa0ba46
PM
6375}
6376
ce5458e8
PM
6377static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
6378{
6379 /* FMOV: gpr to or from float, double, or top half of quad fp reg,
6380 * without conversion.
6381 */
6382
6383 if (itof) {
ce5458e8 6384 TCGv_i64 tcg_rn = cpu_reg(s, rn);
9a9f1f59 6385 TCGv_i64 tmp;
ce5458e8
PM
6386
6387 switch (type) {
6388 case 0:
ce5458e8 6389 /* 32 bit */
9a9f1f59 6390 tmp = tcg_temp_new_i64();
ce5458e8 6391 tcg_gen_ext32u_i64(tmp, tcg_rn);
9a9f1f59 6392 write_fp_dreg(s, rd, tmp);
ce5458e8
PM
6393 tcg_temp_free_i64(tmp);
6394 break;
ce5458e8 6395 case 1:
ce5458e8 6396 /* 64 bit */
9a9f1f59 6397 write_fp_dreg(s, rd, tcg_rn);
ce5458e8 6398 break;
ce5458e8
PM
6399 case 2:
6400 /* 64 bit to top half. */
90e49638 6401 tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(s, rd));
9a9f1f59 6402 clear_vec_high(s, true, rd);
ce5458e8 6403 break;
68130236
RH
6404 case 3:
6405 /* 16 bit */
6406 tmp = tcg_temp_new_i64();
6407 tcg_gen_ext16u_i64(tmp, tcg_rn);
6408 write_fp_dreg(s, rd, tmp);
6409 tcg_temp_free_i64(tmp);
6410 break;
6411 default:
6412 g_assert_not_reached();
ce5458e8
PM
6413 }
6414 } else {
ce5458e8
PM
6415 TCGv_i64 tcg_rd = cpu_reg(s, rd);
6416
6417 switch (type) {
6418 case 0:
6419 /* 32 bit */
90e49638 6420 tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_32));
ce5458e8 6421 break;
ce5458e8
PM
6422 case 1:
6423 /* 64 bit */
90e49638 6424 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_64));
e2f90565
PM
6425 break;
6426 case 2:
6427 /* 64 bits from top half */
90e49638 6428 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(s, rn));
ce5458e8 6429 break;
68130236
RH
6430 case 3:
6431 /* 16 bit */
6432 tcg_gen_ld16u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_16));
6433 break;
6434 default:
6435 g_assert_not_reached();
ce5458e8
PM
6436 }
6437 }
6438}
6439
4ce31af4 6440/* Floating point <-> integer conversions
faa0ba46
PM
6441 * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
6442 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
c436d406 6443 * | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
faa0ba46
PM
6444 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
6445 */
6446static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
6447{
ce5458e8
PM
6448 int rd = extract32(insn, 0, 5);
6449 int rn = extract32(insn, 5, 5);
6450 int opcode = extract32(insn, 16, 3);
6451 int rmode = extract32(insn, 19, 2);
6452 int type = extract32(insn, 22, 2);
6453 bool sbit = extract32(insn, 29, 1);
6454 bool sf = extract32(insn, 31, 1);
6455
c436d406
WN
6456 if (sbit) {
6457 unallocated_encoding(s);
6458 return;
6459 }
6460
6461 if (opcode > 5) {
ce5458e8
PM
6462 /* FMOV */
6463 bool itof = opcode & 1;
6464
c436d406
WN
6465 if (rmode >= 2) {
6466 unallocated_encoding(s);
6467 return;
6468 }
6469
ce5458e8
PM
6470 switch (sf << 3 | type << 1 | rmode) {
6471 case 0x0: /* 32 bit */
6472 case 0xa: /* 64 bit */
6473 case 0xd: /* 64 bit to top half of quad */
6474 break;
68130236
RH
6475 case 0x6: /* 16-bit float, 32-bit int */
6476 case 0xe: /* 16-bit float, 64-bit int */
5763190f 6477 if (dc_isar_feature(aa64_fp16, s)) {
68130236
RH
6478 break;
6479 }
6480 /* fallthru */
ce5458e8
PM
6481 default:
6482 /* all other sf/type/rmode combinations are invalid */
6483 unallocated_encoding(s);
8c738d43 6484 return;
ce5458e8
PM
6485 }
6486
8c6afa6a
PM
6487 if (!fp_access_check(s)) {
6488 return;
6489 }
ce5458e8
PM
6490 handle_fmov(s, rd, rn, type, itof);
6491 } else {
6492 /* actual FP conversions */
c436d406
WN
6493 bool itof = extract32(opcode, 1, 1);
6494
564a0632
RH
6495 if (rmode != 0 && opcode > 1) {
6496 unallocated_encoding(s);
6497 return;
6498 }
6499 switch (type) {
6500 case 0: /* float32 */
6501 case 1: /* float64 */
6502 break;
6503 case 3: /* float16 */
5763190f 6504 if (dc_isar_feature(aa64_fp16, s)) {
564a0632
RH
6505 break;
6506 }
6507 /* fallthru */
6508 default:
c436d406
WN
6509 unallocated_encoding(s);
6510 return;
6511 }
6512
8c6afa6a
PM
6513 if (!fp_access_check(s)) {
6514 return;
6515 }
c436d406 6516 handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
ce5458e8 6517 }
faa0ba46
PM
6518}
6519
6520/* FP-specific subcases of table C3-6 (SIMD and FP data processing)
6521 * 31 30 29 28 25 24 0
6522 * +---+---+---+---------+-----------------------------+
6523 * | | 0 | | 1 1 1 1 | |
6524 * +---+---+---+---------+-----------------------------+
6525 */
6526static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
6527{
6528 if (extract32(insn, 24, 1)) {
6529 /* Floating point data-processing (3 source) */
6530 disas_fp_3src(s, insn);
6531 } else if (extract32(insn, 21, 1) == 0) {
6532 /* Floating point to fixed point conversions */
6533 disas_fp_fixed_conv(s, insn);
6534 } else {
6535 switch (extract32(insn, 10, 2)) {
6536 case 1:
6537 /* Floating point conditional compare */
6538 disas_fp_ccomp(s, insn);
6539 break;
6540 case 2:
6541 /* Floating point data-processing (2 source) */
6542 disas_fp_2src(s, insn);
6543 break;
6544 case 3:
6545 /* Floating point conditional select */
6546 disas_fp_csel(s, insn);
6547 break;
6548 case 0:
6549 switch (ctz32(extract32(insn, 12, 4))) {
6550 case 0: /* [15:12] == xxx1 */
6551 /* Floating point immediate */
6552 disas_fp_imm(s, insn);
6553 break;
6554 case 1: /* [15:12] == xx10 */
6555 /* Floating point compare */
6556 disas_fp_compare(s, insn);
6557 break;
6558 case 2: /* [15:12] == x100 */
6559 /* Floating point data-processing (1 source) */
6560 disas_fp_1src(s, insn);
6561 break;
6562 case 3: /* [15:12] == 1000 */
6563 unallocated_encoding(s);
6564 break;
6565 default: /* [15:12] == 0000 */
6566 /* Floating point <-> integer conversions */
6567 disas_fp_int_conv(s, insn);
6568 break;
6569 }
6570 break;
6571 }
6572 }
6573}
6574
5c73747f
PM
6575static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
6576 int pos)
6577{
6578 /* Extract 64 bits from the middle of two concatenated 64 bit
6579 * vector register slices left:right. The extracted bits start
6580 * at 'pos' bits into the right (least significant) side.
6581 * We return the result in tcg_right, and guarantee not to
6582 * trash tcg_left.
6583 */
6584 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
6585 assert(pos > 0 && pos < 64);
6586
6587 tcg_gen_shri_i64(tcg_right, tcg_right, pos);
6588 tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos);
6589 tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp);
6590
6591 tcg_temp_free_i64(tcg_tmp);
6592}
6593
4ce31af4 6594/* EXT
384b26fb
AB
6595 * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0
6596 * +---+---+-------------+-----+---+------+---+------+---+------+------+
6597 * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd |
6598 * +---+---+-------------+-----+---+------+---+------+---+------+------+
6599 */
6600static void disas_simd_ext(DisasContext *s, uint32_t insn)
6601{
5c73747f
PM
6602 int is_q = extract32(insn, 30, 1);
6603 int op2 = extract32(insn, 22, 2);
6604 int imm4 = extract32(insn, 11, 4);
6605 int rm = extract32(insn, 16, 5);
6606 int rn = extract32(insn, 5, 5);
6607 int rd = extract32(insn, 0, 5);
6608 int pos = imm4 << 3;
6609 TCGv_i64 tcg_resl, tcg_resh;
6610
6611 if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) {
6612 unallocated_encoding(s);
6613 return;
6614 }
6615
8c6afa6a
PM
6616 if (!fp_access_check(s)) {
6617 return;
6618 }
6619
5c73747f
PM
6620 tcg_resh = tcg_temp_new_i64();
6621 tcg_resl = tcg_temp_new_i64();
6622
6623 /* Vd gets bits starting at pos bits into Vm:Vn. This is
6624 * either extracting 128 bits from a 128:128 concatenation, or
6625 * extracting 64 bits from a 64:64 concatenation.
6626 */
6627 if (!is_q) {
6628 read_vec_element(s, tcg_resl, rn, 0, MO_64);
6629 if (pos != 0) {
6630 read_vec_element(s, tcg_resh, rm, 0, MO_64);
6631 do_ext64(s, tcg_resh, tcg_resl, pos);
6632 }
6633 tcg_gen_movi_i64(tcg_resh, 0);
6634 } else {
6635 TCGv_i64 tcg_hh;
6636 typedef struct {
6637 int reg;
6638 int elt;
6639 } EltPosns;
6640 EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} };
6641 EltPosns *elt = eltposns;
6642
6643 if (pos >= 64) {
6644 elt++;
6645 pos -= 64;
6646 }
6647
6648 read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64);
6649 elt++;
6650 read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64);
6651 elt++;
6652 if (pos != 0) {
6653 do_ext64(s, tcg_resh, tcg_resl, pos);
6654 tcg_hh = tcg_temp_new_i64();
6655 read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64);
6656 do_ext64(s, tcg_hh, tcg_resh, pos);
6657 tcg_temp_free_i64(tcg_hh);
6658 }
6659 }
6660
6661 write_vec_element(s, tcg_resl, rd, 0, MO_64);
6662 tcg_temp_free_i64(tcg_resl);
6663 write_vec_element(s, tcg_resh, rd, 1, MO_64);
6664 tcg_temp_free_i64(tcg_resh);
384b26fb
AB
6665}
6666
4ce31af4 6667/* TBL/TBX
384b26fb
AB
6668 * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0
6669 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
6670 * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd |
6671 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
6672 */
6673static void disas_simd_tb(DisasContext *s, uint32_t insn)
6674{
7c51048f
MM
6675 int op2 = extract32(insn, 22, 2);
6676 int is_q = extract32(insn, 30, 1);
6677 int rm = extract32(insn, 16, 5);
6678 int rn = extract32(insn, 5, 5);
6679 int rd = extract32(insn, 0, 5);
6680 int is_tblx = extract32(insn, 12, 1);
6681 int len = extract32(insn, 13, 2);
6682 TCGv_i64 tcg_resl, tcg_resh, tcg_idx;
6683 TCGv_i32 tcg_regno, tcg_numregs;
6684
6685 if (op2 != 0) {
6686 unallocated_encoding(s);
6687 return;
6688 }
6689
8c6afa6a
PM
6690 if (!fp_access_check(s)) {
6691 return;
6692 }
6693
7c51048f
MM
6694 /* This does a table lookup: for every byte element in the input
6695 * we index into a table formed from up to four vector registers,
6696 * and then the output is the result of the lookups. Our helper
6697 * function does the lookup operation for a single 64 bit part of
6698 * the input.
6699 */
6700 tcg_resl = tcg_temp_new_i64();
6701 tcg_resh = tcg_temp_new_i64();
6702
6703 if (is_tblx) {
6704 read_vec_element(s, tcg_resl, rd, 0, MO_64);
6705 } else {
6706 tcg_gen_movi_i64(tcg_resl, 0);
6707 }
6708 if (is_tblx && is_q) {
6709 read_vec_element(s, tcg_resh, rd, 1, MO_64);
6710 } else {
6711 tcg_gen_movi_i64(tcg_resh, 0);
6712 }
6713
6714 tcg_idx = tcg_temp_new_i64();
6715 tcg_regno = tcg_const_i32(rn);
6716 tcg_numregs = tcg_const_i32(len + 1);
6717 read_vec_element(s, tcg_idx, rm, 0, MO_64);
6718 gen_helper_simd_tbl(tcg_resl, cpu_env, tcg_resl, tcg_idx,
6719 tcg_regno, tcg_numregs);
6720 if (is_q) {
6721 read_vec_element(s, tcg_idx, rm, 1, MO_64);
6722 gen_helper_simd_tbl(tcg_resh, cpu_env, tcg_resh, tcg_idx,
6723 tcg_regno, tcg_numregs);
6724 }
6725 tcg_temp_free_i64(tcg_idx);
6726 tcg_temp_free_i32(tcg_regno);
6727 tcg_temp_free_i32(tcg_numregs);
6728
6729 write_vec_element(s, tcg_resl, rd, 0, MO_64);
6730 tcg_temp_free_i64(tcg_resl);
6731 write_vec_element(s, tcg_resh, rd, 1, MO_64);
6732 tcg_temp_free_i64(tcg_resh);
384b26fb
AB
6733}
6734
4ce31af4 6735/* ZIP/UZP/TRN
384b26fb
AB
6736 * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
6737 * +---+---+-------------+------+---+------+---+------------------+------+
6738 * | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd |
6739 * +---+---+-------------+------+---+------+---+------------------+------+
6740 */
6741static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
6742{
5fa5469c
MM
6743 int rd = extract32(insn, 0, 5);
6744 int rn = extract32(insn, 5, 5);
6745 int rm = extract32(insn, 16, 5);
6746 int size = extract32(insn, 22, 2);
6747 /* opc field bits [1:0] indicate ZIP/UZP/TRN;
6748 * bit 2 indicates 1 vs 2 variant of the insn.
6749 */
6750 int opcode = extract32(insn, 12, 2);
6751 bool part = extract32(insn, 14, 1);
6752 bool is_q = extract32(insn, 30, 1);
6753 int esize = 8 << size;
6754 int i, ofs;
6755 int datasize = is_q ? 128 : 64;
6756 int elements = datasize / esize;
6757 TCGv_i64 tcg_res, tcg_resl, tcg_resh;
6758
6759 if (opcode == 0 || (size == 3 && !is_q)) {
6760 unallocated_encoding(s);
6761 return;
6762 }
6763
8c6afa6a
PM
6764 if (!fp_access_check(s)) {
6765 return;
6766 }
6767
5fa5469c
MM
6768 tcg_resl = tcg_const_i64(0);
6769 tcg_resh = tcg_const_i64(0);
6770 tcg_res = tcg_temp_new_i64();
6771
6772 for (i = 0; i < elements; i++) {
6773 switch (opcode) {
6774 case 1: /* UZP1/2 */
6775 {
6776 int midpoint = elements / 2;
6777 if (i < midpoint) {
6778 read_vec_element(s, tcg_res, rn, 2 * i + part, size);
6779 } else {
6780 read_vec_element(s, tcg_res, rm,
6781 2 * (i - midpoint) + part, size);
6782 }
6783 break;
6784 }
6785 case 2: /* TRN1/2 */
6786 if (i & 1) {
6787 read_vec_element(s, tcg_res, rm, (i & ~1) + part, size);
6788 } else {
6789 read_vec_element(s, tcg_res, rn, (i & ~1) + part, size);
6790 }
6791 break;
6792 case 3: /* ZIP1/2 */
6793 {
6794 int base = part * elements / 2;
6795 if (i & 1) {
6796 read_vec_element(s, tcg_res, rm, base + (i >> 1), size);
6797 } else {
6798 read_vec_element(s, tcg_res, rn, base + (i >> 1), size);
6799 }
6800 break;
6801 }
6802 default:
6803 g_assert_not_reached();
6804 }
6805
6806 ofs = i * esize;
6807 if (ofs < 64) {
6808 tcg_gen_shli_i64(tcg_res, tcg_res, ofs);
6809 tcg_gen_or_i64(tcg_resl, tcg_resl, tcg_res);
6810 } else {
6811 tcg_gen_shli_i64(tcg_res, tcg_res, ofs - 64);
6812 tcg_gen_or_i64(tcg_resh, tcg_resh, tcg_res);
6813 }
6814 }
6815
6816 tcg_temp_free_i64(tcg_res);
6817
6818 write_vec_element(s, tcg_resl, rd, 0, MO_64);
6819 tcg_temp_free_i64(tcg_resl);
6820 write_vec_element(s, tcg_resh, rd, 1, MO_64);
6821 tcg_temp_free_i64(tcg_resh);
384b26fb
AB
6822}
6823
807cdd50
AB
6824/*
6825 * do_reduction_op helper
6826 *
6827 * This mirrors the Reduce() pseudocode in the ARM ARM. It is
6828 * important for correct NaN propagation that we do these
6829 * operations in exactly the order specified by the pseudocode.
6830 *
6831 * This is a recursive function, TCG temps should be freed by the
6832 * calling function once it is done with the values.
6833 */
6834static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn,
6835 int esize, int size, int vmap, TCGv_ptr fpst)
6836{
6837 if (esize == size) {
6838 int element;
6839 TCGMemOp msize = esize == 16 ? MO_16 : MO_32;
6840 TCGv_i32 tcg_elem;
6841
6842 /* We should have one register left here */
6843 assert(ctpop8(vmap) == 1);
6844 element = ctz32(vmap);
6845 assert(element < 8);
6846
6847 tcg_elem = tcg_temp_new_i32();
6848 read_vec_element_i32(s, tcg_elem, rn, element, msize);
6849 return tcg_elem;
4a0ff1ce 6850 } else {
807cdd50
AB
6851 int bits = size / 2;
6852 int shift = ctpop8(vmap) / 2;
6853 int vmap_lo = (vmap >> shift) & vmap;
6854 int vmap_hi = (vmap & ~vmap_lo);
6855 TCGv_i32 tcg_hi, tcg_lo, tcg_res;
6856
6857 tcg_hi = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_hi, fpst);
6858 tcg_lo = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_lo, fpst);
6859 tcg_res = tcg_temp_new_i32();
6860
6861 switch (fpopcode) {
6862 case 0x0c: /* fmaxnmv half-precision */
6863 gen_helper_advsimd_maxnumh(tcg_res, tcg_lo, tcg_hi, fpst);
6864 break;
6865 case 0x0f: /* fmaxv half-precision */
6866 gen_helper_advsimd_maxh(tcg_res, tcg_lo, tcg_hi, fpst);
6867 break;
6868 case 0x1c: /* fminnmv half-precision */
6869 gen_helper_advsimd_minnumh(tcg_res, tcg_lo, tcg_hi, fpst);
6870 break;
6871 case 0x1f: /* fminv half-precision */
6872 gen_helper_advsimd_minh(tcg_res, tcg_lo, tcg_hi, fpst);
6873 break;
6874 case 0x2c: /* fmaxnmv */
6875 gen_helper_vfp_maxnums(tcg_res, tcg_lo, tcg_hi, fpst);
6876 break;
6877 case 0x2f: /* fmaxv */
6878 gen_helper_vfp_maxs(tcg_res, tcg_lo, tcg_hi, fpst);
6879 break;
6880 case 0x3c: /* fminnmv */
6881 gen_helper_vfp_minnums(tcg_res, tcg_lo, tcg_hi, fpst);
6882 break;
6883 case 0x3f: /* fminv */
6884 gen_helper_vfp_mins(tcg_res, tcg_lo, tcg_hi, fpst);
6885 break;
6886 default:
6887 g_assert_not_reached();
4a0ff1ce 6888 }
807cdd50
AB
6889
6890 tcg_temp_free_i32(tcg_hi);
6891 tcg_temp_free_i32(tcg_lo);
6892 return tcg_res;
4a0ff1ce
MM
6893 }
6894}
6895
4ce31af4 6896/* AdvSIMD across lanes
384b26fb
AB
6897 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
6898 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
6899 * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
6900 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
6901 */
6902static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
6903{
4a0ff1ce
MM
6904 int rd = extract32(insn, 0, 5);
6905 int rn = extract32(insn, 5, 5);
6906 int size = extract32(insn, 22, 2);
6907 int opcode = extract32(insn, 12, 5);
6908 bool is_q = extract32(insn, 30, 1);
6909 bool is_u = extract32(insn, 29, 1);
6910 bool is_fp = false;
6911 bool is_min = false;
6912 int esize;
6913 int elements;
6914 int i;
6915 TCGv_i64 tcg_res, tcg_elt;
6916
6917 switch (opcode) {
6918 case 0x1b: /* ADDV */
6919 if (is_u) {
6920 unallocated_encoding(s);
6921 return;
6922 }
6923 /* fall through */
6924 case 0x3: /* SADDLV, UADDLV */
6925 case 0xa: /* SMAXV, UMAXV */
6926 case 0x1a: /* SMINV, UMINV */
6927 if (size == 3 || (size == 2 && !is_q)) {
6928 unallocated_encoding(s);
6929 return;
6930 }
6931 break;
6932 case 0xc: /* FMAXNMV, FMINNMV */
6933 case 0xf: /* FMAXV, FMINV */
807cdd50
AB
6934 /* Bit 1 of size field encodes min vs max and the actual size
6935 * depends on the encoding of the U bit. If not set (and FP16
6936 * enabled) then we do half-precision float instead of single
6937 * precision.
4a0ff1ce
MM
6938 */
6939 is_min = extract32(size, 1, 1);
6940 is_fp = true;
5763190f 6941 if (!is_u && dc_isar_feature(aa64_fp16, s)) {
807cdd50
AB
6942 size = 1;
6943 } else if (!is_u || !is_q || extract32(size, 0, 1)) {
6944 unallocated_encoding(s);
6945 return;
6946 } else {
6947 size = 2;
6948 }
4a0ff1ce
MM
6949 break;
6950 default:
6951 unallocated_encoding(s);
6952 return;
6953 }
6954
8c6afa6a
PM
6955 if (!fp_access_check(s)) {
6956 return;
6957 }
6958
4a0ff1ce
MM
6959 esize = 8 << size;
6960 elements = (is_q ? 128 : 64) / esize;
6961
6962 tcg_res = tcg_temp_new_i64();
6963 tcg_elt = tcg_temp_new_i64();
6964
6965 /* These instructions operate across all lanes of a vector
6966 * to produce a single result. We can guarantee that a 64
6967 * bit intermediate is sufficient:
6968 * + for [US]ADDLV the maximum element size is 32 bits, and
6969 * the result type is 64 bits
6970 * + for FMAX*V, FMIN*V, ADDV the intermediate type is the
6971 * same as the element size, which is 32 bits at most
6972 * For the integer operations we can choose to work at 64
6973 * or 32 bits and truncate at the end; for simplicity
6974 * we use 64 bits always. The floating point
6975 * ops do require 32 bit intermediates, though.
6976 */
6977 if (!is_fp) {
6978 read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN));
6979
6980 for (i = 1; i < elements; i++) {
6981 read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN));
6982
6983 switch (opcode) {
6984 case 0x03: /* SADDLV / UADDLV */
6985 case 0x1b: /* ADDV */
6986 tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt);
6987 break;
6988 case 0x0a: /* SMAXV / UMAXV */
ecb8ab8d
RH
6989 if (is_u) {
6990 tcg_gen_umax_i64(tcg_res, tcg_res, tcg_elt);
6991 } else {
6992 tcg_gen_smax_i64(tcg_res, tcg_res, tcg_elt);
6993 }
4a0ff1ce
MM
6994 break;
6995 case 0x1a: /* SMINV / UMINV */
ecb8ab8d
RH
6996 if (is_u) {
6997 tcg_gen_umin_i64(tcg_res, tcg_res, tcg_elt);
6998 } else {
6999 tcg_gen_smin_i64(tcg_res, tcg_res, tcg_elt);
7000 }
4a0ff1ce
MM
7001 break;
7002 default:
7003 g_assert_not_reached();
7004 }
7005
7006 }
7007 } else {
807cdd50
AB
7008 /* Floating point vector reduction ops which work across 32
7009 * bit (single) or 16 bit (half-precision) intermediates.
4a0ff1ce
MM
7010 * Note that correct NaN propagation requires that we do these
7011 * operations in exactly the order specified by the pseudocode.
7012 */
807cdd50
AB
7013 TCGv_ptr fpst = get_fpstatus_ptr(size == MO_16);
7014 int fpopcode = opcode | is_min << 4 | is_u << 5;
7015 int vmap = (1 << elements) - 1;
7016 TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, esize,
7017 (is_q ? 128 : 64), vmap, fpst);
7018 tcg_gen_extu_i32_i64(tcg_res, tcg_res32);
7019 tcg_temp_free_i32(tcg_res32);
4a0ff1ce
MM
7020 tcg_temp_free_ptr(fpst);
7021 }
7022
7023 tcg_temp_free_i64(tcg_elt);
7024
7025 /* Now truncate the result to the width required for the final output */
7026 if (opcode == 0x03) {
7027 /* SADDLV, UADDLV: result is 2*esize */
7028 size++;
7029 }
7030
7031 switch (size) {
7032 case 0:
7033 tcg_gen_ext8u_i64(tcg_res, tcg_res);
7034 break;
7035 case 1:
7036 tcg_gen_ext16u_i64(tcg_res, tcg_res);
7037 break;
7038 case 2:
7039 tcg_gen_ext32u_i64(tcg_res, tcg_res);
7040 break;
7041 case 3:
7042 break;
7043 default:
7044 g_assert_not_reached();
7045 }
7046
7047 write_fp_dreg(s, rd, tcg_res);
7048 tcg_temp_free_i64(tcg_res);
384b26fb
AB
7049}
7050
4ce31af4 7051/* DUP (Element, Vector)
67bb9389
AB
7052 *
7053 * 31 30 29 21 20 16 15 10 9 5 4 0
7054 * +---+---+-------------------+--------+-------------+------+------+
7055 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
7056 * +---+---+-------------------+--------+-------------+------+------+
7057 *
7058 * size: encoded in imm5 (see ARM ARM LowestSetBit())
7059 */
7060static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
7061 int imm5)
7062{
7063 int size = ctz32(imm5);
861a1ded 7064 int index = imm5 >> (size + 1);
67bb9389
AB
7065
7066 if (size > 3 || (size == 3 && !is_q)) {
7067 unallocated_encoding(s);
7068 return;
7069 }
7070
8c6afa6a
PM
7071 if (!fp_access_check(s)) {
7072 return;
7073 }
7074
861a1ded
RH
7075 tcg_gen_gvec_dup_mem(size, vec_full_reg_offset(s, rd),
7076 vec_reg_offset(s, rn, index, size),
7077 is_q ? 16 : 8, vec_full_reg_size(s));
67bb9389
AB
7078}
7079
4ce31af4 7080/* DUP (element, scalar)
360a6f2d
PM
7081 * 31 21 20 16 15 10 9 5 4 0
7082 * +-----------------------+--------+-------------+------+------+
7083 * | 0 1 0 1 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
7084 * +-----------------------+--------+-------------+------+------+
7085 */
7086static void handle_simd_dupes(DisasContext *s, int rd, int rn,
7087 int imm5)
7088{
7089 int size = ctz32(imm5);
7090 int index;
7091 TCGv_i64 tmp;
7092
7093 if (size > 3) {
7094 unallocated_encoding(s);
7095 return;
7096 }
7097
8c6afa6a
PM
7098 if (!fp_access_check(s)) {
7099 return;
7100 }
7101
360a6f2d
PM
7102 index = imm5 >> (size + 1);
7103
7104 /* This instruction just extracts the specified element and
7105 * zero-extends it into the bottom of the destination register.
7106 */
7107 tmp = tcg_temp_new_i64();
7108 read_vec_element(s, tmp, rn, index, size);
7109 write_fp_dreg(s, rd, tmp);
7110 tcg_temp_free_i64(tmp);
7111}
7112
4ce31af4 7113/* DUP (General)
67bb9389
AB
7114 *
7115 * 31 30 29 21 20 16 15 10 9 5 4 0
7116 * +---+---+-------------------+--------+-------------+------+------+
7117 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 1 1 | Rn | Rd |
7118 * +---+---+-------------------+--------+-------------+------+------+
7119 *
7120 * size: encoded in imm5 (see ARM ARM LowestSetBit())
7121 */
7122static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
7123 int imm5)
7124{
7125 int size = ctz32(imm5);
861a1ded 7126 uint32_t dofs, oprsz, maxsz;
67bb9389
AB
7127
7128 if (size > 3 || ((size == 3) && !is_q)) {
7129 unallocated_encoding(s);
7130 return;
7131 }
8c6afa6a
PM
7132
7133 if (!fp_access_check(s)) {
7134 return;
7135 }
7136
861a1ded
RH
7137 dofs = vec_full_reg_offset(s, rd);
7138 oprsz = is_q ? 16 : 8;
7139 maxsz = vec_full_reg_size(s);
7140
7141 tcg_gen_gvec_dup_i64(size, dofs, oprsz, maxsz, cpu_reg(s, rn));
67bb9389
AB
7142}
7143
4ce31af4 7144/* INS (Element)
67bb9389
AB
7145 *
7146 * 31 21 20 16 15 14 11 10 9 5 4 0
7147 * +-----------------------+--------+------------+---+------+------+
7148 * | 0 1 1 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
7149 * +-----------------------+--------+------------+---+------+------+
7150 *
7151 * size: encoded in imm5 (see ARM ARM LowestSetBit())
7152 * index: encoded in imm5<4:size+1>
7153 */
7154static void handle_simd_inse(DisasContext *s, int rd, int rn,
7155 int imm4, int imm5)
7156{
7157 int size = ctz32(imm5);
7158 int src_index, dst_index;
7159 TCGv_i64 tmp;
7160
7161 if (size > 3) {
7162 unallocated_encoding(s);
7163 return;
7164 }
8c6afa6a
PM
7165
7166 if (!fp_access_check(s)) {
7167 return;
7168 }
7169
67bb9389
AB
7170 dst_index = extract32(imm5, 1+size, 5);
7171 src_index = extract32(imm4, size, 4);
7172
7173 tmp = tcg_temp_new_i64();
7174
7175 read_vec_element(s, tmp, rn, src_index, size);
7176 write_vec_element(s, tmp, rd, dst_index, size);
7177
7178 tcg_temp_free_i64(tmp);
7179}
7180
7181
4ce31af4 7182/* INS (General)
67bb9389
AB
7183 *
7184 * 31 21 20 16 15 10 9 5 4 0
7185 * +-----------------------+--------+-------------+------+------+
7186 * | 0 1 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 1 1 1 | Rn | Rd |
7187 * +-----------------------+--------+-------------+------+------+
7188 *
7189 * size: encoded in imm5 (see ARM ARM LowestSetBit())
7190 * index: encoded in imm5<4:size+1>
7191 */
7192static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
7193{
7194 int size = ctz32(imm5);
7195 int idx;
7196
7197 if (size > 3) {
7198 unallocated_encoding(s);
7199 return;
7200 }
7201
8c6afa6a
PM
7202 if (!fp_access_check(s)) {
7203 return;
7204 }
7205
67bb9389
AB
7206 idx = extract32(imm5, 1 + size, 4 - size);
7207 write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
7208}
7209
7210/*
4ce31af4
PM
7211 * UMOV (General)
7212 * SMOV (General)
67bb9389
AB
7213 *
7214 * 31 30 29 21 20 16 15 12 10 9 5 4 0
7215 * +---+---+-------------------+--------+-------------+------+------+
7216 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 1 U 1 1 | Rn | Rd |
7217 * +---+---+-------------------+--------+-------------+------+------+
7218 *
7219 * U: unsigned when set
7220 * size: encoded in imm5 (see ARM ARM LowestSetBit())
7221 */
7222static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
7223 int rn, int rd, int imm5)
7224{
7225 int size = ctz32(imm5);
7226 int element;
7227 TCGv_i64 tcg_rd;
7228
7229 /* Check for UnallocatedEncodings */
7230 if (is_signed) {
7231 if (size > 2 || (size == 2 && !is_q)) {
7232 unallocated_encoding(s);
7233 return;
7234 }
7235 } else {
7236 if (size > 3
7237 || (size < 3 && is_q)
7238 || (size == 3 && !is_q)) {
7239 unallocated_encoding(s);
7240 return;
7241 }
7242 }
8c6afa6a
PM
7243
7244 if (!fp_access_check(s)) {
7245 return;
7246 }
7247
67bb9389
AB
7248 element = extract32(imm5, 1+size, 4);
7249
7250 tcg_rd = cpu_reg(s, rd);
7251 read_vec_element(s, tcg_rd, rn, element, size | (is_signed ? MO_SIGN : 0));
7252 if (is_signed && !is_q) {
7253 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
7254 }
7255}
7256
4ce31af4 7257/* AdvSIMD copy
384b26fb
AB
7258 * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
7259 * +---+---+----+-----------------+------+---+------+---+------+------+
7260 * | 0 | Q | op | 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
7261 * +---+---+----+-----------------+------+---+------+---+------+------+
7262 */
7263static void disas_simd_copy(DisasContext *s, uint32_t insn)
7264{
67bb9389
AB
7265 int rd = extract32(insn, 0, 5);
7266 int rn = extract32(insn, 5, 5);
7267 int imm4 = extract32(insn, 11, 4);
7268 int op = extract32(insn, 29, 1);
7269 int is_q = extract32(insn, 30, 1);
7270 int imm5 = extract32(insn, 16, 5);
7271
7272 if (op) {
7273 if (is_q) {
7274 /* INS (element) */
7275 handle_simd_inse(s, rd, rn, imm4, imm5);
7276 } else {
7277 unallocated_encoding(s);
7278 }
7279 } else {
7280 switch (imm4) {
7281 case 0:
7282 /* DUP (element - vector) */
7283 handle_simd_dupe(s, is_q, rd, rn, imm5);
7284 break;
7285 case 1:
7286 /* DUP (general) */
7287 handle_simd_dupg(s, is_q, rd, rn, imm5);
7288 break;
7289 case 3:
7290 if (is_q) {
7291 /* INS (general) */
7292 handle_simd_insg(s, rd, rn, imm5);
7293 } else {
7294 unallocated_encoding(s);
7295 }
7296 break;
7297 case 5:
7298 case 7:
7299 /* UMOV/SMOV (is_q indicates 32/64; imm4 indicates signedness) */
7300 handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
7301 break;
7302 default:
7303 unallocated_encoding(s);
7304 break;
7305 }
7306 }
384b26fb
AB
7307}
7308
4ce31af4 7309/* AdvSIMD modified immediate
384b26fb
AB
7310 * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0
7311 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
7312 * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd |
7313 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
f3f8c4f4
AB
7314 *
7315 * There are a number of operations that can be carried out here:
7316 * MOVI - move (shifted) imm into register
7317 * MVNI - move inverted (shifted) imm into register
7318 * ORR - bitwise OR of (shifted) imm with register
7319 * BIC - bitwise clear of (shifted) imm with register
70b4e6a4
AB
7320 * With ARMv8.2 we also have:
7321 * FMOV half-precision
384b26fb
AB
7322 */
7323static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
7324{
f3f8c4f4
AB
7325 int rd = extract32(insn, 0, 5);
7326 int cmode = extract32(insn, 12, 4);
7327 int cmode_3_1 = extract32(cmode, 1, 3);
7328 int cmode_0 = extract32(cmode, 0, 1);
7329 int o2 = extract32(insn, 11, 1);
7330 uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
7331 bool is_neg = extract32(insn, 29, 1);
7332 bool is_q = extract32(insn, 30, 1);
7333 uint64_t imm = 0;
f3f8c4f4
AB
7334
7335 if (o2 != 0 || ((cmode == 0xf) && is_neg && !is_q)) {
70b4e6a4 7336 /* Check for FMOV (vector, immediate) - half-precision */
5763190f 7337 if (!(dc_isar_feature(aa64_fp16, s) && o2 && cmode == 0xf)) {
70b4e6a4
AB
7338 unallocated_encoding(s);
7339 return;
7340 }
f3f8c4f4
AB
7341 }
7342
8c6afa6a
PM
7343 if (!fp_access_check(s)) {
7344 return;
7345 }
7346
f3f8c4f4
AB
7347 /* See AdvSIMDExpandImm() in ARM ARM */
7348 switch (cmode_3_1) {
7349 case 0: /* Replicate(Zeros(24):imm8, 2) */
7350 case 1: /* Replicate(Zeros(16):imm8:Zeros(8), 2) */
7351 case 2: /* Replicate(Zeros(8):imm8:Zeros(16), 2) */
7352 case 3: /* Replicate(imm8:Zeros(24), 2) */
7353 {
7354 int shift = cmode_3_1 * 8;
7355 imm = bitfield_replicate(abcdefgh << shift, 32);
7356 break;
7357 }
7358 case 4: /* Replicate(Zeros(8):imm8, 4) */
7359 case 5: /* Replicate(imm8:Zeros(8), 4) */
7360 {
7361 int shift = (cmode_3_1 & 0x1) * 8;
7362 imm = bitfield_replicate(abcdefgh << shift, 16);
7363 break;
7364 }
7365 case 6:
7366 if (cmode_0) {
7367 /* Replicate(Zeros(8):imm8:Ones(16), 2) */
7368 imm = (abcdefgh << 16) | 0xffff;
7369 } else {
7370 /* Replicate(Zeros(16):imm8:Ones(8), 2) */
7371 imm = (abcdefgh << 8) | 0xff;
7372 }
7373 imm = bitfield_replicate(imm, 32);
7374 break;
7375 case 7:
7376 if (!cmode_0 && !is_neg) {
7377 imm = bitfield_replicate(abcdefgh, 8);
7378 } else if (!cmode_0 && is_neg) {
7379 int i;
7380 imm = 0;
7381 for (i = 0; i < 8; i++) {
7382 if ((abcdefgh) & (1 << i)) {
7383 imm |= 0xffULL << (i * 8);
7384 }
7385 }
7386 } else if (cmode_0) {
7387 if (is_neg) {
7388 imm = (abcdefgh & 0x3f) << 48;
7389 if (abcdefgh & 0x80) {
7390 imm |= 0x8000000000000000ULL;
7391 }
7392 if (abcdefgh & 0x40) {
7393 imm |= 0x3fc0000000000000ULL;
7394 } else {
7395 imm |= 0x4000000000000000ULL;
7396 }
7397 } else {
70b4e6a4
AB
7398 if (o2) {
7399 /* FMOV (vector, immediate) - half-precision */
7400 imm = vfp_expand_imm(MO_16, abcdefgh);
7401 /* now duplicate across the lanes */
7402 imm = bitfield_replicate(imm, 16);
f3f8c4f4 7403 } else {
70b4e6a4
AB
7404 imm = (abcdefgh & 0x3f) << 19;
7405 if (abcdefgh & 0x80) {
7406 imm |= 0x80000000;
7407 }
7408 if (abcdefgh & 0x40) {
7409 imm |= 0x3e000000;
7410 } else {
7411 imm |= 0x40000000;
7412 }
7413 imm |= (imm << 32);
f3f8c4f4 7414 }
f3f8c4f4
AB
7415 }
7416 }
7417 break;
70b4e6a4
AB
7418 default:
7419 fprintf(stderr, "%s: cmode_3_1: %x\n", __func__, cmode_3_1);
7420 g_assert_not_reached();
f3f8c4f4
AB
7421 }
7422
7423 if (cmode_3_1 != 7 && is_neg) {
7424 imm = ~imm;
7425 }
7426
861a1ded
RH
7427 if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) {
7428 /* MOVI or MVNI, with MVNI negation handled above. */
7429 tcg_gen_gvec_dup64i(vec_full_reg_offset(s, rd), is_q ? 16 : 8,
7430 vec_full_reg_size(s), imm);
7431 } else {
064e265d
RH
7432 /* ORR or BIC, with BIC negation to AND handled above. */
7433 if (is_neg) {
7434 gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_andi, MO_64);
7435 } else {
7436 gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_ori, MO_64);
f3f8c4f4 7437 }
861a1ded 7438 }
384b26fb
AB
7439}
7440
4ce31af4 7441/* AdvSIMD scalar copy
384b26fb
AB
7442 * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
7443 * +-----+----+-----------------+------+---+------+---+------+------+
7444 * | 0 1 | op | 1 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
7445 * +-----+----+-----------------+------+---+------+---+------+------+
7446 */
7447static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn)
7448{
360a6f2d
PM
7449 int rd = extract32(insn, 0, 5);
7450 int rn = extract32(insn, 5, 5);
7451 int imm4 = extract32(insn, 11, 4);
7452 int imm5 = extract32(insn, 16, 5);
7453 int op = extract32(insn, 29, 1);
7454
7455 if (op != 0 || imm4 != 0) {
7456 unallocated_encoding(s);
7457 return;
7458 }
7459
7460 /* DUP (element, scalar) */
7461 handle_simd_dupes(s, rd, rn, imm5);
384b26fb
AB
7462}
7463
4ce31af4 7464/* AdvSIMD scalar pairwise
384b26fb
AB
7465 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
7466 * +-----+---+-----------+------+-----------+--------+-----+------+------+
7467 * | 0 1 | U | 1 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
7468 * +-----+---+-----------+------+-----------+--------+-----+------+------+
7469 */
7470static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
7471{
3720a7ea
PM
7472 int u = extract32(insn, 29, 1);
7473 int size = extract32(insn, 22, 2);
7474 int opcode = extract32(insn, 12, 5);
7475 int rn = extract32(insn, 5, 5);
7476 int rd = extract32(insn, 0, 5);
7477 TCGv_ptr fpst;
7478
7479 /* For some ops (the FP ones), size[1] is part of the encoding.
7480 * For ADDP strictly it is not but size[1] is always 1 for valid
7481 * encodings.
7482 */
7483 opcode |= (extract32(size, 1, 1) << 5);
7484
7485 switch (opcode) {
7486 case 0x3b: /* ADDP */
7487 if (u || size != 3) {
7488 unallocated_encoding(s);
7489 return;
7490 }
8c6afa6a
PM
7491 if (!fp_access_check(s)) {
7492 return;
7493 }
7494
f764718d 7495 fpst = NULL;
3720a7ea
PM
7496 break;
7497 case 0xc: /* FMAXNMP */
7498 case 0xd: /* FADDP */
7499 case 0xf: /* FMAXP */
7500 case 0x2c: /* FMINNMP */
7501 case 0x2f: /* FMINP */
5c36d895 7502 /* FP op, size[0] is 32 or 64 bit*/
3720a7ea 7503 if (!u) {
5763190f 7504 if (!dc_isar_feature(aa64_fp16, s)) {
5c36d895
AB
7505 unallocated_encoding(s);
7506 return;
7507 } else {
7508 size = MO_16;
7509 }
7510 } else {
7511 size = extract32(size, 0, 1) ? MO_64 : MO_32;
3720a7ea 7512 }
5c36d895 7513
8c6afa6a
PM
7514 if (!fp_access_check(s)) {
7515 return;
7516 }
7517
5c36d895 7518 fpst = get_fpstatus_ptr(size == MO_16);
3720a7ea
PM
7519 break;
7520 default:
7521 unallocated_encoding(s);
7522 return;
7523 }
7524
5c36d895 7525 if (size == MO_64) {
3720a7ea
PM
7526 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7527 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7528 TCGv_i64 tcg_res = tcg_temp_new_i64();
7529
7530 read_vec_element(s, tcg_op1, rn, 0, MO_64);
7531 read_vec_element(s, tcg_op2, rn, 1, MO_64);
7532
7533 switch (opcode) {
7534 case 0x3b: /* ADDP */
7535 tcg_gen_add_i64(tcg_res, tcg_op1, tcg_op2);
7536 break;
7537 case 0xc: /* FMAXNMP */
7538 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
7539 break;
7540 case 0xd: /* FADDP */
7541 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
7542 break;
7543 case 0xf: /* FMAXP */
7544 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
7545 break;
7546 case 0x2c: /* FMINNMP */
7547 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
7548 break;
7549 case 0x2f: /* FMINP */
7550 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
7551 break;
7552 default:
7553 g_assert_not_reached();
7554 }
7555
7556 write_fp_dreg(s, rd, tcg_res);
7557
7558 tcg_temp_free_i64(tcg_op1);
7559 tcg_temp_free_i64(tcg_op2);
7560 tcg_temp_free_i64(tcg_res);
7561 } else {
7562 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7563 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7564 TCGv_i32 tcg_res = tcg_temp_new_i32();
7565
5c36d895
AB
7566 read_vec_element_i32(s, tcg_op1, rn, 0, size);
7567 read_vec_element_i32(s, tcg_op2, rn, 1, size);
3720a7ea 7568
5c36d895
AB
7569 if (size == MO_16) {
7570 switch (opcode) {
7571 case 0xc: /* FMAXNMP */
7572 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
7573 break;
7574 case 0xd: /* FADDP */
7575 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
7576 break;
7577 case 0xf: /* FMAXP */
7578 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
7579 break;
7580 case 0x2c: /* FMINNMP */
7581 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
7582 break;
7583 case 0x2f: /* FMINP */
7584 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
7585 break;
7586 default:
7587 g_assert_not_reached();
7588 }
7589 } else {
7590 switch (opcode) {
7591 case 0xc: /* FMAXNMP */
7592 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
7593 break;
7594 case 0xd: /* FADDP */
7595 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
7596 break;
7597 case 0xf: /* FMAXP */
7598 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
7599 break;
7600 case 0x2c: /* FMINNMP */
7601 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
7602 break;
7603 case 0x2f: /* FMINP */
7604 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
7605 break;
7606 default:
7607 g_assert_not_reached();
7608 }
3720a7ea
PM
7609 }
7610
7611 write_fp_sreg(s, rd, tcg_res);
7612
7613 tcg_temp_free_i32(tcg_op1);
7614 tcg_temp_free_i32(tcg_op2);
7615 tcg_temp_free_i32(tcg_res);
7616 }
7617
f764718d 7618 if (fpst) {
3720a7ea
PM
7619 tcg_temp_free_ptr(fpst);
7620 }
384b26fb
AB
7621}
7622
4d1cef84
AB
7623/*
7624 * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate)
7625 *
7626 * This code is handles the common shifting code and is used by both
7627 * the vector and scalar code.
7628 */
7629static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
7630 TCGv_i64 tcg_rnd, bool accumulate,
7631 bool is_u, int size, int shift)
7632{
7633 bool extended_result = false;
f764718d 7634 bool round = tcg_rnd != NULL;
4d1cef84
AB
7635 int ext_lshift = 0;
7636 TCGv_i64 tcg_src_hi;
7637
7638 if (round && size == 3) {
7639 extended_result = true;
7640 ext_lshift = 64 - shift;
7641 tcg_src_hi = tcg_temp_new_i64();
7642 } else if (shift == 64) {
7643 if (!accumulate && is_u) {
7644 /* result is zero */
7645 tcg_gen_movi_i64(tcg_res, 0);
7646 return;
7647 }
7648 }
7649
7650 /* Deal with the rounding step */
7651 if (round) {
7652 if (extended_result) {
7653 TCGv_i64 tcg_zero = tcg_const_i64(0);
7654 if (!is_u) {
7655 /* take care of sign extending tcg_res */
7656 tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63);
7657 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
7658 tcg_src, tcg_src_hi,
7659 tcg_rnd, tcg_zero);
7660 } else {
7661 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
7662 tcg_src, tcg_zero,
7663 tcg_rnd, tcg_zero);
7664 }
7665 tcg_temp_free_i64(tcg_zero);
7666 } else {
7667 tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd);
7668 }
7669 }
7670
7671 /* Now do the shift right */
7672 if (round && extended_result) {
7673 /* extended case, >64 bit precision required */
7674 if (ext_lshift == 0) {
7675 /* special case, only high bits matter */
7676 tcg_gen_mov_i64(tcg_src, tcg_src_hi);
7677 } else {
7678 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
7679 tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift);
7680 tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi);
7681 }
7682 } else {
7683 if (is_u) {
7684 if (shift == 64) {
7685 /* essentially shifting in 64 zeros */
7686 tcg_gen_movi_i64(tcg_src, 0);
7687 } else {
7688 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
7689 }
7690 } else {
7691 if (shift == 64) {
7692 /* effectively extending the sign-bit */
7693 tcg_gen_sari_i64(tcg_src, tcg_src, 63);
7694 } else {
7695 tcg_gen_sari_i64(tcg_src, tcg_src, shift);
7696 }
7697 }
7698 }
7699
7700 if (accumulate) {
7701 tcg_gen_add_i64(tcg_res, tcg_res, tcg_src);
7702 } else {
7703 tcg_gen_mov_i64(tcg_res, tcg_src);
7704 }
7705
7706 if (extended_result) {
7707 tcg_temp_free_i64(tcg_src_hi);
7708 }
7709}
7710
4d1cef84
AB
7711/* SSHR[RA]/USHR[RA] - Scalar shift right (optional rounding/accumulate) */
7712static void handle_scalar_simd_shri(DisasContext *s,
7713 bool is_u, int immh, int immb,
7714 int opcode, int rn, int rd)
7715{
7716 const int size = 3;
7717 int immhb = immh << 3 | immb;
7718 int shift = 2 * (8 << size) - immhb;
7719 bool accumulate = false;
7720 bool round = false;
37a706ad 7721 bool insert = false;
4d1cef84
AB
7722 TCGv_i64 tcg_rn;
7723 TCGv_i64 tcg_rd;
7724 TCGv_i64 tcg_round;
7725
7726 if (!extract32(immh, 3, 1)) {
7727 unallocated_encoding(s);
7728 return;
7729 }
7730
8c6afa6a
PM
7731 if (!fp_access_check(s)) {
7732 return;
7733 }
7734
4d1cef84
AB
7735 switch (opcode) {
7736 case 0x02: /* SSRA / USRA (accumulate) */
7737 accumulate = true;
7738 break;
7739 case 0x04: /* SRSHR / URSHR (rounding) */
7740 round = true;
7741 break;
7742 case 0x06: /* SRSRA / URSRA (accum + rounding) */
7743 accumulate = round = true;
7744 break;
37a706ad
PM
7745 case 0x08: /* SRI */
7746 insert = true;
7747 break;
4d1cef84
AB
7748 }
7749
7750 if (round) {
7751 uint64_t round_const = 1ULL << (shift - 1);
7752 tcg_round = tcg_const_i64(round_const);
7753 } else {
f764718d 7754 tcg_round = NULL;
4d1cef84
AB
7755 }
7756
7757 tcg_rn = read_fp_dreg(s, rn);
37a706ad 7758 tcg_rd = (accumulate || insert) ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
4d1cef84 7759
37a706ad 7760 if (insert) {
cdb45a60
RH
7761 /* shift count same as element size is valid but does nothing;
7762 * special case to avoid potential shift by 64.
7763 */
7764 int esize = 8 << size;
7765 if (shift != esize) {
7766 tcg_gen_shri_i64(tcg_rn, tcg_rn, shift);
7767 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, 0, esize - shift);
7768 }
37a706ad
PM
7769 } else {
7770 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
7771 accumulate, is_u, size, shift);
7772 }
4d1cef84
AB
7773
7774 write_fp_dreg(s, rd, tcg_rd);
7775
7776 tcg_temp_free_i64(tcg_rn);
7777 tcg_temp_free_i64(tcg_rd);
7778 if (round) {
7779 tcg_temp_free_i64(tcg_round);
7780 }
7781}
7782
7783/* SHL/SLI - Scalar shift left */
7784static void handle_scalar_simd_shli(DisasContext *s, bool insert,
7785 int immh, int immb, int opcode,
7786 int rn, int rd)
7787{
7788 int size = 32 - clz32(immh) - 1;
7789 int immhb = immh << 3 | immb;
7790 int shift = immhb - (8 << size);
7791 TCGv_i64 tcg_rn = new_tmp_a64(s);
7792 TCGv_i64 tcg_rd = new_tmp_a64(s);
7793
7794 if (!extract32(immh, 3, 1)) {
7795 unallocated_encoding(s);
7796 return;
7797 }
7798
8c6afa6a
PM
7799 if (!fp_access_check(s)) {
7800 return;
7801 }
7802
4d1cef84
AB
7803 tcg_rn = read_fp_dreg(s, rn);
7804 tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
7805
cdb45a60
RH
7806 if (insert) {
7807 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, shift, 64 - shift);
7808 } else {
7809 tcg_gen_shli_i64(tcg_rd, tcg_rn, shift);
7810 }
4d1cef84
AB
7811
7812 write_fp_dreg(s, rd, tcg_rd);
7813
7814 tcg_temp_free_i64(tcg_rn);
7815 tcg_temp_free_i64(tcg_rd);
7816}
7817
c1b876b2
AB
7818/* SQSHRN/SQSHRUN - Saturating (signed/unsigned) shift right with
7819 * (signed/unsigned) narrowing */
7820static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q,
7821 bool is_u_shift, bool is_u_narrow,
7822 int immh, int immb, int opcode,
7823 int rn, int rd)
7824{
7825 int immhb = immh << 3 | immb;
7826 int size = 32 - clz32(immh) - 1;
7827 int esize = 8 << size;
7828 int shift = (2 * esize) - immhb;
7829 int elements = is_scalar ? 1 : (64 / esize);
7830 bool round = extract32(opcode, 0, 1);
7831 TCGMemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN);
7832 TCGv_i64 tcg_rn, tcg_rd, tcg_round;
7833 TCGv_i32 tcg_rd_narrowed;
7834 TCGv_i64 tcg_final;
7835
7836 static NeonGenNarrowEnvFn * const signed_narrow_fns[4][2] = {
7837 { gen_helper_neon_narrow_sat_s8,
7838 gen_helper_neon_unarrow_sat8 },
7839 { gen_helper_neon_narrow_sat_s16,
7840 gen_helper_neon_unarrow_sat16 },
7841 { gen_helper_neon_narrow_sat_s32,
7842 gen_helper_neon_unarrow_sat32 },
7843 { NULL, NULL },
7844 };
7845 static NeonGenNarrowEnvFn * const unsigned_narrow_fns[4] = {
7846 gen_helper_neon_narrow_sat_u8,
7847 gen_helper_neon_narrow_sat_u16,
7848 gen_helper_neon_narrow_sat_u32,
7849 NULL
7850 };
7851 NeonGenNarrowEnvFn *narrowfn;
7852
7853 int i;
7854
7855 assert(size < 4);
7856
7857 if (extract32(immh, 3, 1)) {
7858 unallocated_encoding(s);
7859 return;
7860 }
7861
8c6afa6a
PM
7862 if (!fp_access_check(s)) {
7863 return;
7864 }
7865
c1b876b2
AB
7866 if (is_u_shift) {
7867 narrowfn = unsigned_narrow_fns[size];
7868 } else {
7869 narrowfn = signed_narrow_fns[size][is_u_narrow ? 1 : 0];
7870 }
7871
7872 tcg_rn = tcg_temp_new_i64();
7873 tcg_rd = tcg_temp_new_i64();
7874 tcg_rd_narrowed = tcg_temp_new_i32();
7875 tcg_final = tcg_const_i64(0);
7876
7877 if (round) {
7878 uint64_t round_const = 1ULL << (shift - 1);
7879 tcg_round = tcg_const_i64(round_const);
7880 } else {
f764718d 7881 tcg_round = NULL;
c1b876b2
AB
7882 }
7883
7884 for (i = 0; i < elements; i++) {
7885 read_vec_element(s, tcg_rn, rn, i, ldop);
7886 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
7887 false, is_u_shift, size+1, shift);
7888 narrowfn(tcg_rd_narrowed, cpu_env, tcg_rd);
7889 tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed);
7890 tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
7891 }
7892
7893 if (!is_q) {
c1b876b2
AB
7894 write_vec_element(s, tcg_final, rd, 0, MO_64);
7895 } else {
7896 write_vec_element(s, tcg_final, rd, 1, MO_64);
7897 }
7898
7899 if (round) {
7900 tcg_temp_free_i64(tcg_round);
7901 }
7902 tcg_temp_free_i64(tcg_rn);
7903 tcg_temp_free_i64(tcg_rd);
7904 tcg_temp_free_i32(tcg_rd_narrowed);
7905 tcg_temp_free_i64(tcg_final);
4ff55bcb
RH
7906
7907 clear_vec_high(s, is_q, rd);
c1b876b2
AB
7908}
7909
a847f32c
PM
7910/* SQSHLU, UQSHL, SQSHL: saturating left shifts */
7911static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q,
7912 bool src_unsigned, bool dst_unsigned,
7913 int immh, int immb, int rn, int rd)
7914{
7915 int immhb = immh << 3 | immb;
7916 int size = 32 - clz32(immh) - 1;
7917 int shift = immhb - (8 << size);
7918 int pass;
7919
7920 assert(immh != 0);
7921 assert(!(scalar && is_q));
7922
7923 if (!scalar) {
7924 if (!is_q && extract32(immh, 3, 1)) {
7925 unallocated_encoding(s);
7926 return;
7927 }
7928
7929 /* Since we use the variable-shift helpers we must
7930 * replicate the shift count into each element of
7931 * the tcg_shift value.
7932 */
7933 switch (size) {
7934 case 0:
7935 shift |= shift << 8;
7936 /* fall through */
7937 case 1:
7938 shift |= shift << 16;
7939 break;
7940 case 2:
7941 case 3:
7942 break;
7943 default:
7944 g_assert_not_reached();
7945 }
7946 }
7947
8c6afa6a
PM
7948 if (!fp_access_check(s)) {
7949 return;
7950 }
7951
a847f32c
PM
7952 if (size == 3) {
7953 TCGv_i64 tcg_shift = tcg_const_i64(shift);
7954 static NeonGenTwo64OpEnvFn * const fns[2][2] = {
7955 { gen_helper_neon_qshl_s64, gen_helper_neon_qshlu_s64 },
7956 { NULL, gen_helper_neon_qshl_u64 },
7957 };
7958 NeonGenTwo64OpEnvFn *genfn = fns[src_unsigned][dst_unsigned];
7959 int maxpass = is_q ? 2 : 1;
7960
7961 for (pass = 0; pass < maxpass; pass++) {
7962 TCGv_i64 tcg_op = tcg_temp_new_i64();
7963
7964 read_vec_element(s, tcg_op, rn, pass, MO_64);
7965 genfn(tcg_op, cpu_env, tcg_op, tcg_shift);
7966 write_vec_element(s, tcg_op, rd, pass, MO_64);
7967
7968 tcg_temp_free_i64(tcg_op);
7969 }
7970 tcg_temp_free_i64(tcg_shift);
4ff55bcb 7971 clear_vec_high(s, is_q, rd);
a847f32c
PM
7972 } else {
7973 TCGv_i32 tcg_shift = tcg_const_i32(shift);
7974 static NeonGenTwoOpEnvFn * const fns[2][2][3] = {
7975 {
7976 { gen_helper_neon_qshl_s8,
7977 gen_helper_neon_qshl_s16,
7978 gen_helper_neon_qshl_s32 },
7979 { gen_helper_neon_qshlu_s8,
7980 gen_helper_neon_qshlu_s16,
7981 gen_helper_neon_qshlu_s32 }
7982 }, {
7983 { NULL, NULL, NULL },
7984 { gen_helper_neon_qshl_u8,
7985 gen_helper_neon_qshl_u16,
7986 gen_helper_neon_qshl_u32 }
7987 }
7988 };
7989 NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size];
7990 TCGMemOp memop = scalar ? size : MO_32;
7991 int maxpass = scalar ? 1 : is_q ? 4 : 2;
7992
7993 for (pass = 0; pass < maxpass; pass++) {
7994 TCGv_i32 tcg_op = tcg_temp_new_i32();
7995
7996 read_vec_element_i32(s, tcg_op, rn, pass, memop);
7997 genfn(tcg_op, cpu_env, tcg_op, tcg_shift);
7998 if (scalar) {
7999 switch (size) {
8000 case 0:
8001 tcg_gen_ext8u_i32(tcg_op, tcg_op);
8002 break;
8003 case 1:
8004 tcg_gen_ext16u_i32(tcg_op, tcg_op);
8005 break;
8006 case 2:
8007 break;
8008 default:
8009 g_assert_not_reached();
8010 }
8011 write_fp_sreg(s, rd, tcg_op);
8012 } else {
8013 write_vec_element_i32(s, tcg_op, rd, pass, MO_32);
8014 }
8015
8016 tcg_temp_free_i32(tcg_op);
8017 }
8018 tcg_temp_free_i32(tcg_shift);
8019
4ff55bcb
RH
8020 if (!scalar) {
8021 clear_vec_high(s, is_q, rd);
a847f32c
PM
8022 }
8023 }
8024}
8025
10113b69
AB
8026/* Common vector code for handling integer to FP conversion */
8027static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
8028 int elements, int is_signed,
8029 int fracbits, int size)
8030{
93193190
AB
8031 TCGv_ptr tcg_fpst = get_fpstatus_ptr(size == MO_16);
8032 TCGv_i32 tcg_shift = NULL;
8033
10113b69
AB
8034 TCGMemOp mop = size | (is_signed ? MO_SIGN : 0);
8035 int pass;
8036
93193190
AB
8037 if (fracbits || size == MO_64) {
8038 tcg_shift = tcg_const_i32(fracbits);
8039 }
8040
8041 if (size == MO_64) {
8042 TCGv_i64 tcg_int64 = tcg_temp_new_i64();
8043 TCGv_i64 tcg_double = tcg_temp_new_i64();
8044
8045 for (pass = 0; pass < elements; pass++) {
8046 read_vec_element(s, tcg_int64, rn, pass, mop);
10113b69 8047
10113b69 8048 if (is_signed) {
93193190 8049 gen_helper_vfp_sqtod(tcg_double, tcg_int64,
10113b69
AB
8050 tcg_shift, tcg_fpst);
8051 } else {
93193190 8052 gen_helper_vfp_uqtod(tcg_double, tcg_int64,
10113b69
AB
8053 tcg_shift, tcg_fpst);
8054 }
8055 if (elements == 1) {
8056 write_fp_dreg(s, rd, tcg_double);
8057 } else {
8058 write_vec_element(s, tcg_double, rd, pass, MO_64);
8059 }
93193190
AB
8060 }
8061
8062 tcg_temp_free_i64(tcg_int64);
8063 tcg_temp_free_i64(tcg_double);
8064
8065 } else {
8066 TCGv_i32 tcg_int32 = tcg_temp_new_i32();
8067 TCGv_i32 tcg_float = tcg_temp_new_i32();
8068
8069 for (pass = 0; pass < elements; pass++) {
8070 read_vec_element_i32(s, tcg_int32, rn, pass, mop);
8071
8072 switch (size) {
8073 case MO_32:
8074 if (fracbits) {
8075 if (is_signed) {
8076 gen_helper_vfp_sltos(tcg_float, tcg_int32,
8077 tcg_shift, tcg_fpst);
8078 } else {
8079 gen_helper_vfp_ultos(tcg_float, tcg_int32,
8080 tcg_shift, tcg_fpst);
8081 }
8082 } else {
8083 if (is_signed) {
8084 gen_helper_vfp_sitos(tcg_float, tcg_int32, tcg_fpst);
8085 } else {
8086 gen_helper_vfp_uitos(tcg_float, tcg_int32, tcg_fpst);
8087 }
8088 }
8089 break;
8090 case MO_16:
8091 if (fracbits) {
8092 if (is_signed) {
8093 gen_helper_vfp_sltoh(tcg_float, tcg_int32,
8094 tcg_shift, tcg_fpst);
8095 } else {
8096 gen_helper_vfp_ultoh(tcg_float, tcg_int32,
8097 tcg_shift, tcg_fpst);
8098 }
8099 } else {
8100 if (is_signed) {
8101 gen_helper_vfp_sitoh(tcg_float, tcg_int32, tcg_fpst);
8102 } else {
8103 gen_helper_vfp_uitoh(tcg_float, tcg_int32, tcg_fpst);
8104 }
8105 }
8106 break;
8107 default:
8108 g_assert_not_reached();
10113b69 8109 }
93193190 8110
10113b69 8111 if (elements == 1) {
93193190 8112 write_fp_sreg(s, rd, tcg_float);
10113b69 8113 } else {
93193190 8114 write_vec_element_i32(s, tcg_float, rd, pass, size);
10113b69 8115 }
10113b69 8116 }
93193190
AB
8117
8118 tcg_temp_free_i32(tcg_int32);
8119 tcg_temp_free_i32(tcg_float);
10113b69
AB
8120 }
8121
10113b69 8122 tcg_temp_free_ptr(tcg_fpst);
93193190
AB
8123 if (tcg_shift) {
8124 tcg_temp_free_i32(tcg_shift);
8125 }
4ff55bcb
RH
8126
8127 clear_vec_high(s, elements << size == 16, rd);
10113b69
AB
8128}
8129
8130/* UCVTF/SCVTF - Integer to FP conversion */
8131static void handle_simd_shift_intfp_conv(DisasContext *s, bool is_scalar,
8132 bool is_q, bool is_u,
8133 int immh, int immb, int opcode,
8134 int rn, int rd)
8135{
a6117fae 8136 int size, elements, fracbits;
10113b69 8137 int immhb = immh << 3 | immb;
10113b69 8138
a6117fae
RH
8139 if (immh & 8) {
8140 size = MO_64;
8141 if (!is_scalar && !is_q) {
8142 unallocated_encoding(s);
8143 return;
8144 }
8145 } else if (immh & 4) {
8146 size = MO_32;
8147 } else if (immh & 2) {
8148 size = MO_16;
5763190f 8149 if (!dc_isar_feature(aa64_fp16, s)) {
a6117fae
RH
8150 unallocated_encoding(s);
8151 return;
8152 }
8153 } else {
8154 /* immh == 0 would be a failure of the decode logic */
8155 g_assert(immh == 1);
10113b69
AB
8156 unallocated_encoding(s);
8157 return;
8158 }
8159
8160 if (is_scalar) {
8161 elements = 1;
8162 } else {
a6117fae 8163 elements = (8 << is_q) >> size;
10113b69 8164 }
a6117fae 8165 fracbits = (16 << size) - immhb;
8c6afa6a
PM
8166
8167 if (!fp_access_check(s)) {
8168 return;
8169 }
8170
10113b69
AB
8171 handle_simd_intfp_conv(s, rd, rn, elements, !is_u, fracbits, size);
8172}
8173
2ed3ea11
PM
8174/* FCVTZS, FVCVTZU - FP to fixedpoint conversion */
8175static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
8176 bool is_q, bool is_u,
8177 int immh, int immb, int rn, int rd)
8178{
2ed3ea11 8179 int immhb = immh << 3 | immb;
d0ba8e74 8180 int pass, size, fracbits;
2ed3ea11
PM
8181 TCGv_ptr tcg_fpstatus;
8182 TCGv_i32 tcg_rmode, tcg_shift;
8183
d0ba8e74
RH
8184 if (immh & 0x8) {
8185 size = MO_64;
8186 if (!is_scalar && !is_q) {
8187 unallocated_encoding(s);
8188 return;
8189 }
8190 } else if (immh & 0x4) {
8191 size = MO_32;
8192 } else if (immh & 0x2) {
8193 size = MO_16;
5763190f 8194 if (!dc_isar_feature(aa64_fp16, s)) {
d0ba8e74
RH
8195 unallocated_encoding(s);
8196 return;
8197 }
8198 } else {
8199 /* Should have split out AdvSIMD modified immediate earlier. */
8200 assert(immh == 1);
2ed3ea11
PM
8201 unallocated_encoding(s);
8202 return;
8203 }
8204
8c6afa6a
PM
8205 if (!fp_access_check(s)) {
8206 return;
8207 }
8208
2ed3ea11
PM
8209 assert(!(is_scalar && is_q));
8210
8211 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(FPROUNDING_ZERO));
d0ba8e74 8212 tcg_fpstatus = get_fpstatus_ptr(size == MO_16);
9b049916 8213 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
d0ba8e74 8214 fracbits = (16 << size) - immhb;
2ed3ea11
PM
8215 tcg_shift = tcg_const_i32(fracbits);
8216
d0ba8e74 8217 if (size == MO_64) {
4063452e 8218 int maxpass = is_scalar ? 1 : 2;
2ed3ea11
PM
8219
8220 for (pass = 0; pass < maxpass; pass++) {
8221 TCGv_i64 tcg_op = tcg_temp_new_i64();
8222
8223 read_vec_element(s, tcg_op, rn, pass, MO_64);
8224 if (is_u) {
8225 gen_helper_vfp_touqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
8226 } else {
8227 gen_helper_vfp_tosqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
8228 }
8229 write_vec_element(s, tcg_op, rd, pass, MO_64);
8230 tcg_temp_free_i64(tcg_op);
8231 }
4ff55bcb 8232 clear_vec_high(s, is_q, rd);
2ed3ea11 8233 } else {
d0ba8e74
RH
8234 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
8235 int maxpass = is_scalar ? 1 : ((8 << is_q) >> size);
2ed3ea11 8236
d0ba8e74
RH
8237 switch (size) {
8238 case MO_16:
2ed3ea11 8239 if (is_u) {
88808a02 8240 fn = gen_helper_vfp_touhh;
2ed3ea11 8241 } else {
88808a02 8242 fn = gen_helper_vfp_toshh;
2ed3ea11 8243 }
d0ba8e74
RH
8244 break;
8245 case MO_32:
2ed3ea11 8246 if (is_u) {
d0ba8e74 8247 fn = gen_helper_vfp_touls;
2ed3ea11 8248 } else {
d0ba8e74 8249 fn = gen_helper_vfp_tosls;
2ed3ea11 8250 }
d0ba8e74
RH
8251 break;
8252 default:
8253 g_assert_not_reached();
8254 }
8255
8256 for (pass = 0; pass < maxpass; pass++) {
8257 TCGv_i32 tcg_op = tcg_temp_new_i32();
8258
8259 read_vec_element_i32(s, tcg_op, rn, pass, size);
8260 fn(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
2ed3ea11
PM
8261 if (is_scalar) {
8262 write_fp_sreg(s, rd, tcg_op);
8263 } else {
d0ba8e74 8264 write_vec_element_i32(s, tcg_op, rd, pass, size);
2ed3ea11
PM
8265 }
8266 tcg_temp_free_i32(tcg_op);
8267 }
4ff55bcb
RH
8268 if (!is_scalar) {
8269 clear_vec_high(s, is_q, rd);
2ed3ea11
PM
8270 }
8271 }
8272
8273 tcg_temp_free_ptr(tcg_fpstatus);
8274 tcg_temp_free_i32(tcg_shift);
9b049916 8275 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
2ed3ea11
PM
8276 tcg_temp_free_i32(tcg_rmode);
8277}
8278
4ce31af4 8279/* AdvSIMD scalar shift by immediate
384b26fb
AB
8280 * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
8281 * +-----+---+-------------+------+------+--------+---+------+------+
8282 * | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
8283 * +-----+---+-------------+------+------+--------+---+------+------+
4d1cef84
AB
8284 *
8285 * This is the scalar version so it works on a fixed sized registers
384b26fb
AB
8286 */
8287static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
8288{
4d1cef84
AB
8289 int rd = extract32(insn, 0, 5);
8290 int rn = extract32(insn, 5, 5);
8291 int opcode = extract32(insn, 11, 5);
8292 int immb = extract32(insn, 16, 3);
8293 int immh = extract32(insn, 19, 4);
8294 bool is_u = extract32(insn, 29, 1);
8295
c1b876b2
AB
8296 if (immh == 0) {
8297 unallocated_encoding(s);
8298 return;
8299 }
8300
4d1cef84 8301 switch (opcode) {
37a706ad
PM
8302 case 0x08: /* SRI */
8303 if (!is_u) {
8304 unallocated_encoding(s);
8305 return;
8306 }
8307 /* fall through */
4d1cef84
AB
8308 case 0x00: /* SSHR / USHR */
8309 case 0x02: /* SSRA / USRA */
8310 case 0x04: /* SRSHR / URSHR */
8311 case 0x06: /* SRSRA / URSRA */
8312 handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd);
8313 break;
8314 case 0x0a: /* SHL / SLI */
8315 handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd);
8316 break;
10113b69
AB
8317 case 0x1c: /* SCVTF, UCVTF */
8318 handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb,
8319 opcode, rn, rd);
8320 break;
c1b876b2
AB
8321 case 0x10: /* SQSHRUN, SQSHRUN2 */
8322 case 0x11: /* SQRSHRUN, SQRSHRUN2 */
8323 if (!is_u) {
8324 unallocated_encoding(s);
8325 return;
8326 }
8327 handle_vec_simd_sqshrn(s, true, false, false, true,
8328 immh, immb, opcode, rn, rd);
8329 break;
8330 case 0x12: /* SQSHRN, SQSHRN2, UQSHRN */
8331 case 0x13: /* SQRSHRN, SQRSHRN2, UQRSHRN, UQRSHRN2 */
8332 handle_vec_simd_sqshrn(s, true, false, is_u, is_u,
8333 immh, immb, opcode, rn, rd);
8334 break;
a566da1b 8335 case 0xc: /* SQSHLU */
a847f32c
PM
8336 if (!is_u) {
8337 unallocated_encoding(s);
8338 return;
8339 }
8340 handle_simd_qshl(s, true, false, false, true, immh, immb, rn, rd);
8341 break;
a566da1b 8342 case 0xe: /* SQSHL, UQSHL */
a847f32c
PM
8343 handle_simd_qshl(s, true, false, is_u, is_u, immh, immb, rn, rd);
8344 break;
a566da1b 8345 case 0x1f: /* FCVTZS, FCVTZU */
2ed3ea11 8346 handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd);
4d1cef84 8347 break;
a566da1b
PM
8348 default:
8349 unallocated_encoding(s);
8350 break;
4d1cef84 8351 }
384b26fb
AB
8352}
8353
4ce31af4 8354/* AdvSIMD scalar three different
384b26fb
AB
8355 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
8356 * +-----+---+-----------+------+---+------+--------+-----+------+------+
8357 * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
8358 * +-----+---+-----------+------+---+------+--------+-----+------+------+
8359 */
8360static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn)
8361{
b033cd3d
PM
8362 bool is_u = extract32(insn, 29, 1);
8363 int size = extract32(insn, 22, 2);
8364 int opcode = extract32(insn, 12, 4);
8365 int rm = extract32(insn, 16, 5);
8366 int rn = extract32(insn, 5, 5);
8367 int rd = extract32(insn, 0, 5);
8368
8369 if (is_u) {
8370 unallocated_encoding(s);
8371 return;
8372 }
8373
8374 switch (opcode) {
8375 case 0x9: /* SQDMLAL, SQDMLAL2 */
8376 case 0xb: /* SQDMLSL, SQDMLSL2 */
8377 case 0xd: /* SQDMULL, SQDMULL2 */
8378 if (size == 0 || size == 3) {
8379 unallocated_encoding(s);
8380 return;
8381 }
8382 break;
8383 default:
8384 unallocated_encoding(s);
8385 return;
8386 }
8387
8c6afa6a
PM
8388 if (!fp_access_check(s)) {
8389 return;
8390 }
8391
b033cd3d
PM
8392 if (size == 2) {
8393 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
8394 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
8395 TCGv_i64 tcg_res = tcg_temp_new_i64();
8396
8397 read_vec_element(s, tcg_op1, rn, 0, MO_32 | MO_SIGN);
8398 read_vec_element(s, tcg_op2, rm, 0, MO_32 | MO_SIGN);
8399
8400 tcg_gen_mul_i64(tcg_res, tcg_op1, tcg_op2);
8401 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, tcg_res, tcg_res);
8402
8403 switch (opcode) {
8404 case 0xd: /* SQDMULL, SQDMULL2 */
8405 break;
8406 case 0xb: /* SQDMLSL, SQDMLSL2 */
8407 tcg_gen_neg_i64(tcg_res, tcg_res);
8408 /* fall through */
8409 case 0x9: /* SQDMLAL, SQDMLAL2 */
8410 read_vec_element(s, tcg_op1, rd, 0, MO_64);
8411 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env,
8412 tcg_res, tcg_op1);
8413 break;
8414 default:
8415 g_assert_not_reached();
8416 }
8417
8418 write_fp_dreg(s, rd, tcg_res);
8419
8420 tcg_temp_free_i64(tcg_op1);
8421 tcg_temp_free_i64(tcg_op2);
8422 tcg_temp_free_i64(tcg_res);
8423 } else {
3d99d931
RH
8424 TCGv_i32 tcg_op1 = read_fp_hreg(s, rn);
8425 TCGv_i32 tcg_op2 = read_fp_hreg(s, rm);
b033cd3d
PM
8426 TCGv_i64 tcg_res = tcg_temp_new_i64();
8427
b033cd3d
PM
8428 gen_helper_neon_mull_s16(tcg_res, tcg_op1, tcg_op2);
8429 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, tcg_res, tcg_res);
8430
8431 switch (opcode) {
8432 case 0xd: /* SQDMULL, SQDMULL2 */
8433 break;
8434 case 0xb: /* SQDMLSL, SQDMLSL2 */
8435 gen_helper_neon_negl_u32(tcg_res, tcg_res);
8436 /* fall through */
8437 case 0x9: /* SQDMLAL, SQDMLAL2 */
8438 {
8439 TCGv_i64 tcg_op3 = tcg_temp_new_i64();
8440 read_vec_element(s, tcg_op3, rd, 0, MO_32);
8441 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env,
8442 tcg_res, tcg_op3);
8443 tcg_temp_free_i64(tcg_op3);
8444 break;
8445 }
8446 default:
8447 g_assert_not_reached();
8448 }
8449
8450 tcg_gen_ext32u_i64(tcg_res, tcg_res);
8451 write_fp_dreg(s, rd, tcg_res);
8452
8453 tcg_temp_free_i32(tcg_op1);
8454 tcg_temp_free_i32(tcg_op2);
8455 tcg_temp_free_i64(tcg_res);
8456 }
384b26fb
AB
8457}
8458
b305dba6
PM
8459static void handle_3same_64(DisasContext *s, int opcode, bool u,
8460 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 tcg_rm)
8461{
8462 /* Handle 64x64->64 opcodes which are shared between the scalar
8463 * and vector 3-same groups. We cover every opcode where size == 3
8464 * is valid in either the three-reg-same (integer, not pairwise)
3840d219 8465 * or scalar-three-reg-same groups.
b305dba6
PM
8466 */
8467 TCGCond cond;
8468
8469 switch (opcode) {
6d9571f7
PM
8470 case 0x1: /* SQADD */
8471 if (u) {
8472 gen_helper_neon_qadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8473 } else {
8474 gen_helper_neon_qadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8475 }
8476 break;
8477 case 0x5: /* SQSUB */
8478 if (u) {
8479 gen_helper_neon_qsub_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8480 } else {
8481 gen_helper_neon_qsub_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8482 }
8483 break;
b305dba6
PM
8484 case 0x6: /* CMGT, CMHI */
8485 /* 64 bit integer comparison, result = test ? (2^64 - 1) : 0.
8486 * We implement this using setcond (test) and then negating.
8487 */
8488 cond = u ? TCG_COND_GTU : TCG_COND_GT;
8489 do_cmop:
8490 tcg_gen_setcond_i64(cond, tcg_rd, tcg_rn, tcg_rm);
8491 tcg_gen_neg_i64(tcg_rd, tcg_rd);
8492 break;
8493 case 0x7: /* CMGE, CMHS */
8494 cond = u ? TCG_COND_GEU : TCG_COND_GE;
8495 goto do_cmop;
8496 case 0x11: /* CMTST, CMEQ */
8497 if (u) {
8498 cond = TCG_COND_EQ;
8499 goto do_cmop;
8500 }
79d61de6 8501 gen_cmtst_i64(tcg_rd, tcg_rn, tcg_rm);
b305dba6 8502 break;
6d9571f7 8503 case 0x8: /* SSHL, USHL */
b305dba6 8504 if (u) {
6d9571f7 8505 gen_helper_neon_shl_u64(tcg_rd, tcg_rn, tcg_rm);
b305dba6 8506 } else {
6d9571f7 8507 gen_helper_neon_shl_s64(tcg_rd, tcg_rn, tcg_rm);
b305dba6
PM
8508 }
8509 break;
b305dba6 8510 case 0x9: /* SQSHL, UQSHL */
6d9571f7
PM
8511 if (u) {
8512 gen_helper_neon_qshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8513 } else {
8514 gen_helper_neon_qshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8515 }
8516 break;
b305dba6 8517 case 0xa: /* SRSHL, URSHL */
6d9571f7
PM
8518 if (u) {
8519 gen_helper_neon_rshl_u64(tcg_rd, tcg_rn, tcg_rm);
8520 } else {
8521 gen_helper_neon_rshl_s64(tcg_rd, tcg_rn, tcg_rm);
8522 }
8523 break;
b305dba6 8524 case 0xb: /* SQRSHL, UQRSHL */
6d9571f7
PM
8525 if (u) {
8526 gen_helper_neon_qrshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8527 } else {
8528 gen_helper_neon_qrshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8529 }
8530 break;
8531 case 0x10: /* ADD, SUB */
8532 if (u) {
8533 tcg_gen_sub_i64(tcg_rd, tcg_rn, tcg_rm);
8534 } else {
8535 tcg_gen_add_i64(tcg_rd, tcg_rn, tcg_rm);
8536 }
8537 break;
b305dba6
PM
8538 default:
8539 g_assert_not_reached();
8540 }
8541}
8542
845ea09a
PM
8543/* Handle the 3-same-operands float operations; shared by the scalar
8544 * and vector encodings. The caller must filter out any encodings
8545 * not allocated for the encoding it is dealing with.
8546 */
8547static void handle_3same_float(DisasContext *s, int size, int elements,
8548 int fpopcode, int rd, int rn, int rm)
8549{
8550 int pass;
d81ce0ef 8551 TCGv_ptr fpst = get_fpstatus_ptr(false);
845ea09a
PM
8552
8553 for (pass = 0; pass < elements; pass++) {
8554 if (size) {
8555 /* Double */
8556 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
8557 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
8558 TCGv_i64 tcg_res = tcg_temp_new_i64();
8559
8560 read_vec_element(s, tcg_op1, rn, pass, MO_64);
8561 read_vec_element(s, tcg_op2, rm, pass, MO_64);
8562
8563 switch (fpopcode) {
057d5f62
PM
8564 case 0x39: /* FMLS */
8565 /* As usual for ARM, separate negation for fused multiply-add */
8566 gen_helper_vfp_negd(tcg_op1, tcg_op1);
8567 /* fall through */
8568 case 0x19: /* FMLA */
8569 read_vec_element(s, tcg_res, rd, pass, MO_64);
8570 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2,
8571 tcg_res, fpst);
8572 break;
845ea09a
PM
8573 case 0x18: /* FMAXNM */
8574 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
8575 break;
8576 case 0x1a: /* FADD */
8577 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
8578 break;
057d5f62
PM
8579 case 0x1b: /* FMULX */
8580 gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
8581 break;
8908f4d1
AB
8582 case 0x1c: /* FCMEQ */
8583 gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8584 break;
845ea09a
PM
8585 case 0x1e: /* FMAX */
8586 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
8587 break;
057d5f62
PM
8588 case 0x1f: /* FRECPS */
8589 gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8590 break;
845ea09a
PM
8591 case 0x38: /* FMINNM */
8592 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
8593 break;
8594 case 0x3a: /* FSUB */
8595 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
8596 break;
8597 case 0x3e: /* FMIN */
8598 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
8599 break;
057d5f62
PM
8600 case 0x3f: /* FRSQRTS */
8601 gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8602 break;
845ea09a
PM
8603 case 0x5b: /* FMUL */
8604 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
8605 break;
8908f4d1
AB
8606 case 0x5c: /* FCMGE */
8607 gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8608 break;
057d5f62
PM
8609 case 0x5d: /* FACGE */
8610 gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8611 break;
845ea09a
PM
8612 case 0x5f: /* FDIV */
8613 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
8614 break;
8615 case 0x7a: /* FABD */
8616 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
8617 gen_helper_vfp_absd(tcg_res, tcg_res);
8618 break;
8908f4d1
AB
8619 case 0x7c: /* FCMGT */
8620 gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8621 break;
057d5f62
PM
8622 case 0x7d: /* FACGT */
8623 gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8624 break;
845ea09a
PM
8625 default:
8626 g_assert_not_reached();
8627 }
8628
8629 write_vec_element(s, tcg_res, rd, pass, MO_64);
8630
8631 tcg_temp_free_i64(tcg_res);
8632 tcg_temp_free_i64(tcg_op1);
8633 tcg_temp_free_i64(tcg_op2);
8634 } else {
8635 /* Single */
8636 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
8637 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
8638 TCGv_i32 tcg_res = tcg_temp_new_i32();
8639
8640 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
8641 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
8642
8643 switch (fpopcode) {
057d5f62
PM
8644 case 0x39: /* FMLS */
8645 /* As usual for ARM, separate negation for fused multiply-add */
8646 gen_helper_vfp_negs(tcg_op1, tcg_op1);
8647 /* fall through */
8648 case 0x19: /* FMLA */
8649 read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8650 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2,
8651 tcg_res, fpst);
8652 break;
845ea09a
PM
8653 case 0x1a: /* FADD */
8654 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
8655 break;
057d5f62
PM
8656 case 0x1b: /* FMULX */
8657 gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
8658 break;
8908f4d1
AB
8659 case 0x1c: /* FCMEQ */
8660 gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8661 break;
845ea09a
PM
8662 case 0x1e: /* FMAX */
8663 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
8664 break;
057d5f62
PM
8665 case 0x1f: /* FRECPS */
8666 gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8667 break;
845ea09a
PM
8668 case 0x18: /* FMAXNM */
8669 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
8670 break;
8671 case 0x38: /* FMINNM */
8672 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
8673 break;
8674 case 0x3a: /* FSUB */
8675 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
8676 break;
8677 case 0x3e: /* FMIN */
8678 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
8679 break;
057d5f62
PM
8680 case 0x3f: /* FRSQRTS */
8681 gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8682 break;
845ea09a
PM
8683 case 0x5b: /* FMUL */
8684 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
8685 break;
8908f4d1
AB
8686 case 0x5c: /* FCMGE */
8687 gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8688 break;
057d5f62
PM
8689 case 0x5d: /* FACGE */
8690 gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8691 break;
845ea09a
PM
8692 case 0x5f: /* FDIV */
8693 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
8694 break;
8695 case 0x7a: /* FABD */
8696 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
8697 gen_helper_vfp_abss(tcg_res, tcg_res);
8698 break;
8908f4d1
AB
8699 case 0x7c: /* FCMGT */
8700 gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8701 break;
057d5f62
PM
8702 case 0x7d: /* FACGT */
8703 gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8704 break;
845ea09a
PM
8705 default:
8706 g_assert_not_reached();
8707 }
8708
8709 if (elements == 1) {
8710 /* scalar single so clear high part */
8711 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
8712
8713 tcg_gen_extu_i32_i64(tcg_tmp, tcg_res);
8714 write_vec_element(s, tcg_tmp, rd, pass, MO_64);
8715 tcg_temp_free_i64(tcg_tmp);
8716 } else {
8717 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8718 }
8719
8720 tcg_temp_free_i32(tcg_res);
8721 tcg_temp_free_i32(tcg_op1);
8722 tcg_temp_free_i32(tcg_op2);
8723 }
8724 }
8725
8726 tcg_temp_free_ptr(fpst);
8727
4ff55bcb 8728 clear_vec_high(s, elements * (size ? 8 : 4) > 8, rd);
845ea09a
PM
8729}
8730
4ce31af4 8731/* AdvSIMD scalar three same
384b26fb
AB
8732 * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
8733 * +-----+---+-----------+------+---+------+--------+---+------+------+
8734 * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
8735 * +-----+---+-----------+------+---+------+--------+---+------+------+
8736 */
8737static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
8738{
b305dba6
PM
8739 int rd = extract32(insn, 0, 5);
8740 int rn = extract32(insn, 5, 5);
8741 int opcode = extract32(insn, 11, 5);
8742 int rm = extract32(insn, 16, 5);
8743 int size = extract32(insn, 22, 2);
8744 bool u = extract32(insn, 29, 1);
b305dba6
PM
8745 TCGv_i64 tcg_rd;
8746
8747 if (opcode >= 0x18) {
8748 /* Floating point: U, size[1] and opcode indicate operation */
8749 int fpopcode = opcode | (extract32(size, 1, 1) << 5) | (u << 6);
8750 switch (fpopcode) {
8751 case 0x1b: /* FMULX */
b305dba6
PM
8752 case 0x1f: /* FRECPS */
8753 case 0x3f: /* FRSQRTS */
b305dba6 8754 case 0x5d: /* FACGE */
b305dba6 8755 case 0x7d: /* FACGT */
8908f4d1
AB
8756 case 0x1c: /* FCMEQ */
8757 case 0x5c: /* FCMGE */
8758 case 0x7c: /* FCMGT */
845ea09a
PM
8759 case 0x7a: /* FABD */
8760 break;
b305dba6
PM
8761 default:
8762 unallocated_encoding(s);
8763 return;
8764 }
845ea09a 8765
8c6afa6a
PM
8766 if (!fp_access_check(s)) {
8767 return;
8768 }
8769
845ea09a
PM
8770 handle_3same_float(s, extract32(size, 0, 1), 1, fpopcode, rd, rn, rm);
8771 return;
b305dba6
PM
8772 }
8773
8774 switch (opcode) {
8775 case 0x1: /* SQADD, UQADD */
8776 case 0x5: /* SQSUB, UQSUB */
c0b2b5fa
PM
8777 case 0x9: /* SQSHL, UQSHL */
8778 case 0xb: /* SQRSHL, UQRSHL */
8779 break;
6d9571f7
PM
8780 case 0x8: /* SSHL, USHL */
8781 case 0xa: /* SRSHL, URSHL */
b305dba6
PM
8782 case 0x6: /* CMGT, CMHI */
8783 case 0x7: /* CMGE, CMHS */
8784 case 0x11: /* CMTST, CMEQ */
8785 case 0x10: /* ADD, SUB (vector) */
8786 if (size != 3) {
8787 unallocated_encoding(s);
8788 return;
8789 }
8790 break;
b305dba6
PM
8791 case 0x16: /* SQDMULH, SQRDMULH (vector) */
8792 if (size != 1 && size != 2) {
8793 unallocated_encoding(s);
8794 return;
8795 }
c0b2b5fa 8796 break;
b305dba6
PM
8797 default:
8798 unallocated_encoding(s);
8799 return;
8800 }
8801
8c6afa6a
PM
8802 if (!fp_access_check(s)) {
8803 return;
8804 }
8805
b305dba6
PM
8806 tcg_rd = tcg_temp_new_i64();
8807
c0b2b5fa
PM
8808 if (size == 3) {
8809 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
8810 TCGv_i64 tcg_rm = read_fp_dreg(s, rm);
8811
8812 handle_3same_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rm);
8813 tcg_temp_free_i64(tcg_rn);
8814 tcg_temp_free_i64(tcg_rm);
8815 } else {
8816 /* Do a single operation on the lowest element in the vector.
8817 * We use the standard Neon helpers and rely on 0 OP 0 == 0 with
8818 * no side effects for all these operations.
8819 * OPTME: special-purpose helpers would avoid doing some
8820 * unnecessary work in the helper for the 8 and 16 bit cases.
8821 */
8822 NeonGenTwoOpEnvFn *genenvfn;
8823 TCGv_i32 tcg_rn = tcg_temp_new_i32();
8824 TCGv_i32 tcg_rm = tcg_temp_new_i32();
8825 TCGv_i32 tcg_rd32 = tcg_temp_new_i32();
8826
8827 read_vec_element_i32(s, tcg_rn, rn, 0, size);
8828 read_vec_element_i32(s, tcg_rm, rm, 0, size);
8829
8830 switch (opcode) {
8831 case 0x1: /* SQADD, UQADD */
8832 {
8833 static NeonGenTwoOpEnvFn * const fns[3][2] = {
8834 { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
8835 { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
8836 { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
8837 };
8838 genenvfn = fns[size][u];
8839 break;
8840 }
8841 case 0x5: /* SQSUB, UQSUB */
8842 {
8843 static NeonGenTwoOpEnvFn * const fns[3][2] = {
8844 { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
8845 { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
8846 { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
8847 };
8848 genenvfn = fns[size][u];
8849 break;
8850 }
8851 case 0x9: /* SQSHL, UQSHL */
8852 {
8853 static NeonGenTwoOpEnvFn * const fns[3][2] = {
8854 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
8855 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
8856 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
8857 };
8858 genenvfn = fns[size][u];
8859 break;
8860 }
8861 case 0xb: /* SQRSHL, UQRSHL */
8862 {
8863 static NeonGenTwoOpEnvFn * const fns[3][2] = {
8864 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
8865 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
8866 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
8867 };
8868 genenvfn = fns[size][u];
8869 break;
8870 }
8871 case 0x16: /* SQDMULH, SQRDMULH */
8872 {
8873 static NeonGenTwoOpEnvFn * const fns[2][2] = {
8874 { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
8875 { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
8876 };
8877 assert(size == 1 || size == 2);
8878 genenvfn = fns[size - 1][u];
8879 break;
8880 }
8881 default:
8882 g_assert_not_reached();
8883 }
8884
8885 genenvfn(tcg_rd32, cpu_env, tcg_rn, tcg_rm);
8886 tcg_gen_extu_i32_i64(tcg_rd, tcg_rd32);
8887 tcg_temp_free_i32(tcg_rd32);
8888 tcg_temp_free_i32(tcg_rn);
8889 tcg_temp_free_i32(tcg_rm);
8890 }
b305dba6
PM
8891
8892 write_fp_dreg(s, rd, tcg_rd);
8893
b305dba6 8894 tcg_temp_free_i64(tcg_rd);
384b26fb
AB
8895}
8896
7c93b774
AB
8897/* AdvSIMD scalar three same FP16
8898 * 31 30 29 28 24 23 22 21 20 16 15 14 13 11 10 9 5 4 0
8899 * +-----+---+-----------+---+-----+------+-----+--------+---+----+----+
8900 * | 0 1 | U | 1 1 1 1 0 | a | 1 0 | Rm | 0 0 | opcode | 1 | Rn | Rd |
8901 * +-----+---+-----------+---+-----+------+-----+--------+---+----+----+
8902 * v: 0101 1110 0100 0000 0000 0100 0000 0000 => 5e400400
8903 * m: 1101 1111 0110 0000 1100 0100 0000 0000 => df60c400
8904 */
8905static void disas_simd_scalar_three_reg_same_fp16(DisasContext *s,
8906 uint32_t insn)
8907{
8908 int rd = extract32(insn, 0, 5);
8909 int rn = extract32(insn, 5, 5);
8910 int opcode = extract32(insn, 11, 3);
8911 int rm = extract32(insn, 16, 5);
8912 bool u = extract32(insn, 29, 1);
8913 bool a = extract32(insn, 23, 1);
8914 int fpopcode = opcode | (a << 3) | (u << 4);
8915 TCGv_ptr fpst;
8916 TCGv_i32 tcg_op1;
8917 TCGv_i32 tcg_op2;
8918 TCGv_i32 tcg_res;
8919
8920 switch (fpopcode) {
8921 case 0x03: /* FMULX */
8922 case 0x04: /* FCMEQ (reg) */
8923 case 0x07: /* FRECPS */
8924 case 0x0f: /* FRSQRTS */
8925 case 0x14: /* FCMGE (reg) */
8926 case 0x15: /* FACGE */
8927 case 0x1a: /* FABD */
8928 case 0x1c: /* FCMGT (reg) */
8929 case 0x1d: /* FACGT */
8930 break;
8931 default:
8932 unallocated_encoding(s);
8933 return;
8934 }
8935
5763190f 8936 if (!dc_isar_feature(aa64_fp16, s)) {
7c93b774
AB
8937 unallocated_encoding(s);
8938 }
8939
8940 if (!fp_access_check(s)) {
8941 return;
8942 }
8943
8944 fpst = get_fpstatus_ptr(true);
8945
3d99d931
RH
8946 tcg_op1 = read_fp_hreg(s, rn);
8947 tcg_op2 = read_fp_hreg(s, rm);
7c93b774
AB
8948 tcg_res = tcg_temp_new_i32();
8949
7c93b774
AB
8950 switch (fpopcode) {
8951 case 0x03: /* FMULX */
8952 gen_helper_advsimd_mulxh(tcg_res, tcg_op1, tcg_op2, fpst);
8953 break;
8954 case 0x04: /* FCMEQ (reg) */
8955 gen_helper_advsimd_ceq_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8956 break;
8957 case 0x07: /* FRECPS */
8958 gen_helper_recpsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8959 break;
8960 case 0x0f: /* FRSQRTS */
8961 gen_helper_rsqrtsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8962 break;
8963 case 0x14: /* FCMGE (reg) */
8964 gen_helper_advsimd_cge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8965 break;
8966 case 0x15: /* FACGE */
8967 gen_helper_advsimd_acge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8968 break;
8969 case 0x1a: /* FABD */
8970 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
8971 tcg_gen_andi_i32(tcg_res, tcg_res, 0x7fff);
8972 break;
8973 case 0x1c: /* FCMGT (reg) */
8974 gen_helper_advsimd_cgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8975 break;
8976 case 0x1d: /* FACGT */
8977 gen_helper_advsimd_acgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
8978 break;
8979 default:
8980 g_assert_not_reached();
8981 }
8982
8983 write_fp_sreg(s, rd, tcg_res);
8984
8985
8986 tcg_temp_free_i32(tcg_res);
8987 tcg_temp_free_i32(tcg_op1);
8988 tcg_temp_free_i32(tcg_op2);
8989 tcg_temp_free_ptr(fpst);
8990}
8991
d9061ec3
RH
8992/* AdvSIMD scalar three same extra
8993 * 31 30 29 28 24 23 22 21 20 16 15 14 11 10 9 5 4 0
8994 * +-----+---+-----------+------+---+------+---+--------+---+----+----+
8995 * | 0 1 | U | 1 1 1 1 0 | size | 0 | Rm | 1 | opcode | 1 | Rn | Rd |
8996 * +-----+---+-----------+------+---+------+---+--------+---+----+----+
8997 */
8998static void disas_simd_scalar_three_reg_same_extra(DisasContext *s,
8999 uint32_t insn)
9000{
9001 int rd = extract32(insn, 0, 5);
9002 int rn = extract32(insn, 5, 5);
9003 int opcode = extract32(insn, 11, 4);
9004 int rm = extract32(insn, 16, 5);
9005 int size = extract32(insn, 22, 2);
9006 bool u = extract32(insn, 29, 1);
9007 TCGv_i32 ele1, ele2, ele3;
9008 TCGv_i64 res;
962fcbf2 9009 bool feature;
d9061ec3
RH
9010
9011 switch (u * 16 + opcode) {
9012 case 0x10: /* SQRDMLAH (vector) */
9013 case 0x11: /* SQRDMLSH (vector) */
9014 if (size != 1 && size != 2) {
9015 unallocated_encoding(s);
9016 return;
9017 }
962fcbf2 9018 feature = dc_isar_feature(aa64_rdm, s);
d9061ec3
RH
9019 break;
9020 default:
9021 unallocated_encoding(s);
9022 return;
9023 }
962fcbf2 9024 if (!feature) {
d9061ec3
RH
9025 unallocated_encoding(s);
9026 return;
9027 }
9028 if (!fp_access_check(s)) {
9029 return;
9030 }
9031
9032 /* Do a single operation on the lowest element in the vector.
9033 * We use the standard Neon helpers and rely on 0 OP 0 == 0
9034 * with no side effects for all these operations.
9035 * OPTME: special-purpose helpers would avoid doing some
9036 * unnecessary work in the helper for the 16 bit cases.
9037 */
9038 ele1 = tcg_temp_new_i32();
9039 ele2 = tcg_temp_new_i32();
9040 ele3 = tcg_temp_new_i32();
9041
9042 read_vec_element_i32(s, ele1, rn, 0, size);
9043 read_vec_element_i32(s, ele2, rm, 0, size);
9044 read_vec_element_i32(s, ele3, rd, 0, size);
9045
9046 switch (opcode) {
9047 case 0x0: /* SQRDMLAH */
9048 if (size == 1) {
9049 gen_helper_neon_qrdmlah_s16(ele3, cpu_env, ele1, ele2, ele3);
9050 } else {
9051 gen_helper_neon_qrdmlah_s32(ele3, cpu_env, ele1, ele2, ele3);
9052 }
9053 break;
9054 case 0x1: /* SQRDMLSH */
9055 if (size == 1) {
9056 gen_helper_neon_qrdmlsh_s16(ele3, cpu_env, ele1, ele2, ele3);
9057 } else {
9058 gen_helper_neon_qrdmlsh_s32(ele3, cpu_env, ele1, ele2, ele3);
9059 }
9060 break;
9061 default:
9062 g_assert_not_reached();
9063 }
9064 tcg_temp_free_i32(ele1);
9065 tcg_temp_free_i32(ele2);
9066
9067 res = tcg_temp_new_i64();
9068 tcg_gen_extu_i32_i64(res, ele3);
9069 tcg_temp_free_i32(ele3);
9070
9071 write_fp_dreg(s, rd, res);
9072 tcg_temp_free_i64(res);
9073}
9074
effa8e06 9075static void handle_2misc_64(DisasContext *s, int opcode, bool u,
04c7c6c2
PM
9076 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn,
9077 TCGv_i32 tcg_rmode, TCGv_ptr tcg_fpstatus)
effa8e06
PM
9078{
9079 /* Handle 64->64 opcodes which are shared between the scalar and
9080 * vector 2-reg-misc groups. We cover every integer opcode where size == 3
f93d0138 9081 * is valid in either group and also the double-precision fp ops.
04c7c6c2
PM
9082 * The caller only need provide tcg_rmode and tcg_fpstatus if the op
9083 * requires them.
effa8e06
PM
9084 */
9085 TCGCond cond;
9086
9087 switch (opcode) {
b05c3068
AB
9088 case 0x4: /* CLS, CLZ */
9089 if (u) {
7539a012 9090 tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
b05c3068 9091 } else {
bc21dbcc 9092 tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
b05c3068
AB
9093 }
9094 break;
86cbc418
PM
9095 case 0x5: /* NOT */
9096 /* This opcode is shared with CNT and RBIT but we have earlier
9097 * enforced that size == 3 if and only if this is the NOT insn.
9098 */
9099 tcg_gen_not_i64(tcg_rd, tcg_rn);
9100 break;
0a79bc87
AB
9101 case 0x7: /* SQABS, SQNEG */
9102 if (u) {
9103 gen_helper_neon_qneg_s64(tcg_rd, cpu_env, tcg_rn);
9104 } else {
9105 gen_helper_neon_qabs_s64(tcg_rd, cpu_env, tcg_rn);
9106 }
9107 break;
effa8e06
PM
9108 case 0xa: /* CMLT */
9109 /* 64 bit integer comparison against zero, result is
9110 * test ? (2^64 - 1) : 0. We implement via setcond(!test) and
9111 * subtracting 1.
9112 */
9113 cond = TCG_COND_LT;
9114 do_cmop:
9115 tcg_gen_setcondi_i64(cond, tcg_rd, tcg_rn, 0);
9116 tcg_gen_neg_i64(tcg_rd, tcg_rd);
9117 break;
9118 case 0x8: /* CMGT, CMGE */
9119 cond = u ? TCG_COND_GE : TCG_COND_GT;
9120 goto do_cmop;
9121 case 0x9: /* CMEQ, CMLE */
9122 cond = u ? TCG_COND_LE : TCG_COND_EQ;
9123 goto do_cmop;
9124 case 0xb: /* ABS, NEG */
9125 if (u) {
9126 tcg_gen_neg_i64(tcg_rd, tcg_rn);
9127 } else {
9128 TCGv_i64 tcg_zero = tcg_const_i64(0);
9129 tcg_gen_neg_i64(tcg_rd, tcg_rn);
9130 tcg_gen_movcond_i64(TCG_COND_GT, tcg_rd, tcg_rn, tcg_zero,
9131 tcg_rn, tcg_rd);
9132 tcg_temp_free_i64(tcg_zero);
9133 }
9134 break;
f93d0138
PM
9135 case 0x2f: /* FABS */
9136 gen_helper_vfp_absd(tcg_rd, tcg_rn);
9137 break;
9138 case 0x6f: /* FNEG */
9139 gen_helper_vfp_negd(tcg_rd, tcg_rn);
9140 break;
f612537e
AB
9141 case 0x7f: /* FSQRT */
9142 gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, cpu_env);
9143 break;
04c7c6c2
PM
9144 case 0x1a: /* FCVTNS */
9145 case 0x1b: /* FCVTMS */
9146 case 0x1c: /* FCVTAS */
9147 case 0x3a: /* FCVTPS */
9148 case 0x3b: /* FCVTZS */
9149 {
9150 TCGv_i32 tcg_shift = tcg_const_i32(0);
9151 gen_helper_vfp_tosqd(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus);
9152 tcg_temp_free_i32(tcg_shift);
9153 break;
9154 }
9155 case 0x5a: /* FCVTNU */
9156 case 0x5b: /* FCVTMU */
9157 case 0x5c: /* FCVTAU */
9158 case 0x7a: /* FCVTPU */
9159 case 0x7b: /* FCVTZU */
9160 {
9161 TCGv_i32 tcg_shift = tcg_const_i32(0);
9162 gen_helper_vfp_touqd(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus);
9163 tcg_temp_free_i32(tcg_shift);
9164 break;
9165 }
03df01ed
PM
9166 case 0x18: /* FRINTN */
9167 case 0x19: /* FRINTM */
9168 case 0x38: /* FRINTP */
9169 case 0x39: /* FRINTZ */
9170 case 0x58: /* FRINTA */
9171 case 0x79: /* FRINTI */
9172 gen_helper_rintd(tcg_rd, tcg_rn, tcg_fpstatus);
9173 break;
9174 case 0x59: /* FRINTX */
9175 gen_helper_rintd_exact(tcg_rd, tcg_rn, tcg_fpstatus);
9176 break;
effa8e06
PM
9177 default:
9178 g_assert_not_reached();
9179 }
9180}
9181
8908f4d1
AB
9182static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
9183 bool is_scalar, bool is_u, bool is_q,
9184 int size, int rn, int rd)
9185{
7d4dd1a7 9186 bool is_double = (size == MO_64);
8c6afa6a
PM
9187 TCGv_ptr fpst;
9188
9189 if (!fp_access_check(s)) {
9190 return;
9191 }
9192
7d4dd1a7 9193 fpst = get_fpstatus_ptr(size == MO_16);
8908f4d1
AB
9194
9195 if (is_double) {
9196 TCGv_i64 tcg_op = tcg_temp_new_i64();
9197 TCGv_i64 tcg_zero = tcg_const_i64(0);
9198 TCGv_i64 tcg_res = tcg_temp_new_i64();
9199 NeonGenTwoDoubleOPFn *genfn;
9200 bool swap = false;
9201 int pass;
9202
9203 switch (opcode) {
9204 case 0x2e: /* FCMLT (zero) */
9205 swap = true;
9206 /* fallthrough */
9207 case 0x2c: /* FCMGT (zero) */
9208 genfn = gen_helper_neon_cgt_f64;
9209 break;
9210 case 0x2d: /* FCMEQ (zero) */
9211 genfn = gen_helper_neon_ceq_f64;
9212 break;
9213 case 0x6d: /* FCMLE (zero) */
9214 swap = true;
9215 /* fall through */
9216 case 0x6c: /* FCMGE (zero) */
9217 genfn = gen_helper_neon_cge_f64;
9218 break;
9219 default:
9220 g_assert_not_reached();
9221 }
9222
9223 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9224 read_vec_element(s, tcg_op, rn, pass, MO_64);
9225 if (swap) {
9226 genfn(tcg_res, tcg_zero, tcg_op, fpst);
9227 } else {
9228 genfn(tcg_res, tcg_op, tcg_zero, fpst);
9229 }
9230 write_vec_element(s, tcg_res, rd, pass, MO_64);
9231 }
8908f4d1
AB
9232 tcg_temp_free_i64(tcg_res);
9233 tcg_temp_free_i64(tcg_zero);
9234 tcg_temp_free_i64(tcg_op);
4ff55bcb
RH
9235
9236 clear_vec_high(s, !is_scalar, rd);
8908f4d1
AB
9237 } else {
9238 TCGv_i32 tcg_op = tcg_temp_new_i32();
9239 TCGv_i32 tcg_zero = tcg_const_i32(0);
9240 TCGv_i32 tcg_res = tcg_temp_new_i32();
9241 NeonGenTwoSingleOPFn *genfn;
9242 bool swap = false;
9243 int pass, maxpasses;
9244
7d4dd1a7
AB
9245 if (size == MO_16) {
9246 switch (opcode) {
9247 case 0x2e: /* FCMLT (zero) */
9248 swap = true;
9249 /* fall through */
9250 case 0x2c: /* FCMGT (zero) */
9251 genfn = gen_helper_advsimd_cgt_f16;
9252 break;
9253 case 0x2d: /* FCMEQ (zero) */
9254 genfn = gen_helper_advsimd_ceq_f16;
9255 break;
9256 case 0x6d: /* FCMLE (zero) */
9257 swap = true;
9258 /* fall through */
9259 case 0x6c: /* FCMGE (zero) */
9260 genfn = gen_helper_advsimd_cge_f16;
9261 break;
9262 default:
9263 g_assert_not_reached();
9264 }
9265 } else {
9266 switch (opcode) {
9267 case 0x2e: /* FCMLT (zero) */
9268 swap = true;
9269 /* fall through */
9270 case 0x2c: /* FCMGT (zero) */
9271 genfn = gen_helper_neon_cgt_f32;
9272 break;
9273 case 0x2d: /* FCMEQ (zero) */
9274 genfn = gen_helper_neon_ceq_f32;
9275 break;
9276 case 0x6d: /* FCMLE (zero) */
9277 swap = true;
9278 /* fall through */
9279 case 0x6c: /* FCMGE (zero) */
9280 genfn = gen_helper_neon_cge_f32;
9281 break;
9282 default:
9283 g_assert_not_reached();
9284 }
8908f4d1
AB
9285 }
9286
9287 if (is_scalar) {
9288 maxpasses = 1;
9289 } else {
7d4dd1a7
AB
9290 int vector_size = 8 << is_q;
9291 maxpasses = vector_size >> size;
8908f4d1
AB
9292 }
9293
9294 for (pass = 0; pass < maxpasses; pass++) {
7d4dd1a7 9295 read_vec_element_i32(s, tcg_op, rn, pass, size);
8908f4d1
AB
9296 if (swap) {
9297 genfn(tcg_res, tcg_zero, tcg_op, fpst);
9298 } else {
9299 genfn(tcg_res, tcg_op, tcg_zero, fpst);
9300 }
9301 if (is_scalar) {
9302 write_fp_sreg(s, rd, tcg_res);
9303 } else {
7d4dd1a7 9304 write_vec_element_i32(s, tcg_res, rd, pass, size);
8908f4d1
AB
9305 }
9306 }
9307 tcg_temp_free_i32(tcg_res);
9308 tcg_temp_free_i32(tcg_zero);
9309 tcg_temp_free_i32(tcg_op);
4ff55bcb
RH
9310 if (!is_scalar) {
9311 clear_vec_high(s, is_q, rd);
8908f4d1
AB
9312 }
9313 }
9314
9315 tcg_temp_free_ptr(fpst);
9316}
9317
8f0c6758
AB
9318static void handle_2misc_reciprocal(DisasContext *s, int opcode,
9319 bool is_scalar, bool is_u, bool is_q,
9320 int size, int rn, int rd)
9321{
9322 bool is_double = (size == 3);
d81ce0ef 9323 TCGv_ptr fpst = get_fpstatus_ptr(false);
8f0c6758
AB
9324
9325 if (is_double) {
9326 TCGv_i64 tcg_op = tcg_temp_new_i64();
9327 TCGv_i64 tcg_res = tcg_temp_new_i64();
9328 int pass;
9329
9330 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9331 read_vec_element(s, tcg_op, rn, pass, MO_64);
9332 switch (opcode) {
b6d4443a
AB
9333 case 0x3d: /* FRECPE */
9334 gen_helper_recpe_f64(tcg_res, tcg_op, fpst);
9335 break;
8f0c6758
AB
9336 case 0x3f: /* FRECPX */
9337 gen_helper_frecpx_f64(tcg_res, tcg_op, fpst);
9338 break;
c2fb418e
AB
9339 case 0x7d: /* FRSQRTE */
9340 gen_helper_rsqrte_f64(tcg_res, tcg_op, fpst);
9341 break;
8f0c6758
AB
9342 default:
9343 g_assert_not_reached();
9344 }
9345 write_vec_element(s, tcg_res, rd, pass, MO_64);
9346 }
8f0c6758
AB
9347 tcg_temp_free_i64(tcg_res);
9348 tcg_temp_free_i64(tcg_op);
4ff55bcb 9349 clear_vec_high(s, !is_scalar, rd);
8f0c6758
AB
9350 } else {
9351 TCGv_i32 tcg_op = tcg_temp_new_i32();
9352 TCGv_i32 tcg_res = tcg_temp_new_i32();
9353 int pass, maxpasses;
9354
9355 if (is_scalar) {
9356 maxpasses = 1;
9357 } else {
9358 maxpasses = is_q ? 4 : 2;
9359 }
9360
9361 for (pass = 0; pass < maxpasses; pass++) {
9362 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
9363
9364 switch (opcode) {
b6d4443a
AB
9365 case 0x3c: /* URECPE */
9366 gen_helper_recpe_u32(tcg_res, tcg_op, fpst);
9367 break;
9368 case 0x3d: /* FRECPE */
9369 gen_helper_recpe_f32(tcg_res, tcg_op, fpst);
9370 break;
8f0c6758
AB
9371 case 0x3f: /* FRECPX */
9372 gen_helper_frecpx_f32(tcg_res, tcg_op, fpst);
9373 break;
c2fb418e
AB
9374 case 0x7d: /* FRSQRTE */
9375 gen_helper_rsqrte_f32(tcg_res, tcg_op, fpst);
9376 break;
8f0c6758
AB
9377 default:
9378 g_assert_not_reached();
9379 }
9380
9381 if (is_scalar) {
9382 write_fp_sreg(s, rd, tcg_res);
9383 } else {
9384 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
9385 }
9386 }
9387 tcg_temp_free_i32(tcg_res);
9388 tcg_temp_free_i32(tcg_op);
4ff55bcb
RH
9389 if (!is_scalar) {
9390 clear_vec_high(s, is_q, rd);
8f0c6758
AB
9391 }
9392 }
9393 tcg_temp_free_ptr(fpst);
9394}
9395
5201c136
AB
9396static void handle_2misc_narrow(DisasContext *s, bool scalar,
9397 int opcode, bool u, bool is_q,
8b092ca9
AB
9398 int size, int rn, int rd)
9399{
9400 /* Handle 2-reg-misc ops which are narrowing (so each 2*size element
9401 * in the source becomes a size element in the destination).
9402 */
9403 int pass;
9404 TCGv_i32 tcg_res[2];
9405 int destelt = is_q ? 2 : 0;
5201c136 9406 int passes = scalar ? 1 : 2;
8b092ca9 9407
5201c136
AB
9408 if (scalar) {
9409 tcg_res[1] = tcg_const_i32(0);
9410 }
9411
9412 for (pass = 0; pass < passes; pass++) {
8b092ca9
AB
9413 TCGv_i64 tcg_op = tcg_temp_new_i64();
9414 NeonGenNarrowFn *genfn = NULL;
9415 NeonGenNarrowEnvFn *genenvfn = NULL;
9416
5201c136
AB
9417 if (scalar) {
9418 read_vec_element(s, tcg_op, rn, pass, size + 1);
9419 } else {
9420 read_vec_element(s, tcg_op, rn, pass, MO_64);
9421 }
8b092ca9
AB
9422 tcg_res[pass] = tcg_temp_new_i32();
9423
9424 switch (opcode) {
9425 case 0x12: /* XTN, SQXTUN */
9426 {
9427 static NeonGenNarrowFn * const xtnfns[3] = {
9428 gen_helper_neon_narrow_u8,
9429 gen_helper_neon_narrow_u16,
ecc7b3aa 9430 tcg_gen_extrl_i64_i32,
8b092ca9
AB
9431 };
9432 static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
9433 gen_helper_neon_unarrow_sat8,
9434 gen_helper_neon_unarrow_sat16,
9435 gen_helper_neon_unarrow_sat32,
9436 };
9437 if (u) {
9438 genenvfn = sqxtunfns[size];
9439 } else {
9440 genfn = xtnfns[size];
9441 }
9442 break;
9443 }
9444 case 0x14: /* SQXTN, UQXTN */
9445 {
9446 static NeonGenNarrowEnvFn * const fns[3][2] = {
9447 { gen_helper_neon_narrow_sat_s8,
9448 gen_helper_neon_narrow_sat_u8 },
9449 { gen_helper_neon_narrow_sat_s16,
9450 gen_helper_neon_narrow_sat_u16 },
9451 { gen_helper_neon_narrow_sat_s32,
9452 gen_helper_neon_narrow_sat_u32 },
9453 };
9454 genenvfn = fns[size][u];
9455 break;
9456 }
9457 case 0x16: /* FCVTN, FCVTN2 */
9458 /* 32 bit to 16 bit or 64 bit to 32 bit float conversion */
9459 if (size == 2) {
9460 gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, cpu_env);
9461 } else {
9462 TCGv_i32 tcg_lo = tcg_temp_new_i32();
9463 TCGv_i32 tcg_hi = tcg_temp_new_i32();
486624fc
AB
9464 TCGv_ptr fpst = get_fpstatus_ptr(false);
9465 TCGv_i32 ahp = get_ahp_flag();
9466
7cb36e18 9467 tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
486624fc
AB
9468 gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
9469 gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
8b092ca9
AB
9470 tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
9471 tcg_temp_free_i32(tcg_lo);
9472 tcg_temp_free_i32(tcg_hi);
486624fc
AB
9473 tcg_temp_free_ptr(fpst);
9474 tcg_temp_free_i32(ahp);
8b092ca9
AB
9475 }
9476 break;
5553955e
PM
9477 case 0x56: /* FCVTXN, FCVTXN2 */
9478 /* 64 bit to 32 bit float conversion
9479 * with von Neumann rounding (round to odd)
9480 */
9481 assert(size == 2);
9482 gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, cpu_env);
9483 break;
8b092ca9
AB
9484 default:
9485 g_assert_not_reached();
9486 }
9487
9488 if (genfn) {
9489 genfn(tcg_res[pass], tcg_op);
9490 } else if (genenvfn) {
9491 genenvfn(tcg_res[pass], cpu_env, tcg_op);
9492 }
9493
9494 tcg_temp_free_i64(tcg_op);
9495 }
9496
9497 for (pass = 0; pass < 2; pass++) {
9498 write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32);
9499 tcg_temp_free_i32(tcg_res[pass]);
9500 }
4ff55bcb 9501 clear_vec_high(s, is_q, rd);
8b092ca9
AB
9502}
9503
09e03735
AB
9504/* Remaining saturating accumulating ops */
9505static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u,
9506 bool is_q, int size, int rn, int rd)
9507{
9508 bool is_double = (size == 3);
9509
9510 if (is_double) {
9511 TCGv_i64 tcg_rn = tcg_temp_new_i64();
9512 TCGv_i64 tcg_rd = tcg_temp_new_i64();
9513 int pass;
9514
9515 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9516 read_vec_element(s, tcg_rn, rn, pass, MO_64);
9517 read_vec_element(s, tcg_rd, rd, pass, MO_64);
9518
9519 if (is_u) { /* USQADD */
9520 gen_helper_neon_uqadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9521 } else { /* SUQADD */
9522 gen_helper_neon_sqadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9523 }
9524 write_vec_element(s, tcg_rd, rd, pass, MO_64);
9525 }
09e03735
AB
9526 tcg_temp_free_i64(tcg_rd);
9527 tcg_temp_free_i64(tcg_rn);
4ff55bcb 9528 clear_vec_high(s, !is_scalar, rd);
09e03735
AB
9529 } else {
9530 TCGv_i32 tcg_rn = tcg_temp_new_i32();
9531 TCGv_i32 tcg_rd = tcg_temp_new_i32();
9532 int pass, maxpasses;
9533
9534 if (is_scalar) {
9535 maxpasses = 1;
9536 } else {
9537 maxpasses = is_q ? 4 : 2;
9538 }
9539
9540 for (pass = 0; pass < maxpasses; pass++) {
9541 if (is_scalar) {
9542 read_vec_element_i32(s, tcg_rn, rn, pass, size);
9543 read_vec_element_i32(s, tcg_rd, rd, pass, size);
9544 } else {
9545 read_vec_element_i32(s, tcg_rn, rn, pass, MO_32);
9546 read_vec_element_i32(s, tcg_rd, rd, pass, MO_32);
9547 }
9548
9549 if (is_u) { /* USQADD */
9550 switch (size) {
9551 case 0:
9552 gen_helper_neon_uqadd_s8(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9553 break;
9554 case 1:
9555 gen_helper_neon_uqadd_s16(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9556 break;
9557 case 2:
9558 gen_helper_neon_uqadd_s32(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9559 break;
9560 default:
9561 g_assert_not_reached();
9562 }
9563 } else { /* SUQADD */
9564 switch (size) {
9565 case 0:
9566 gen_helper_neon_sqadd_u8(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9567 break;
9568 case 1:
9569 gen_helper_neon_sqadd_u16(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9570 break;
9571 case 2:
9572 gen_helper_neon_sqadd_u32(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9573 break;
9574 default:
9575 g_assert_not_reached();
9576 }
9577 }
9578
9579 if (is_scalar) {
9580 TCGv_i64 tcg_zero = tcg_const_i64(0);
9581 write_vec_element(s, tcg_zero, rd, 0, MO_64);
9582 tcg_temp_free_i64(tcg_zero);
9583 }
9584 write_vec_element_i32(s, tcg_rd, rd, pass, MO_32);
9585 }
09e03735
AB
9586 tcg_temp_free_i32(tcg_rd);
9587 tcg_temp_free_i32(tcg_rn);
4ff55bcb 9588 clear_vec_high(s, is_q, rd);
09e03735
AB
9589 }
9590}
9591
4ce31af4 9592/* AdvSIMD scalar two reg misc
384b26fb
AB
9593 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
9594 * +-----+---+-----------+------+-----------+--------+-----+------+------+
9595 * | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
9596 * +-----+---+-----------+------+-----------+--------+-----+------+------+
9597 */
9598static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
9599{
effa8e06
PM
9600 int rd = extract32(insn, 0, 5);
9601 int rn = extract32(insn, 5, 5);
9602 int opcode = extract32(insn, 12, 5);
9603 int size = extract32(insn, 22, 2);
9604 bool u = extract32(insn, 29, 1);
04c7c6c2
PM
9605 bool is_fcvt = false;
9606 int rmode;
9607 TCGv_i32 tcg_rmode;
9608 TCGv_ptr tcg_fpstatus;
effa8e06
PM
9609
9610 switch (opcode) {
09e03735 9611 case 0x3: /* USQADD / SUQADD*/
8c6afa6a
PM
9612 if (!fp_access_check(s)) {
9613 return;
9614 }
09e03735
AB
9615 handle_2misc_satacc(s, true, u, false, size, rn, rd);
9616 return;
0a79bc87
AB
9617 case 0x7: /* SQABS / SQNEG */
9618 break;
effa8e06
PM
9619 case 0xa: /* CMLT */
9620 if (u) {
9621 unallocated_encoding(s);
9622 return;
9623 }
9624 /* fall through */
9625 case 0x8: /* CMGT, CMGE */
9626 case 0x9: /* CMEQ, CMLE */
9627 case 0xb: /* ABS, NEG */
9628 if (size != 3) {
9629 unallocated_encoding(s);
9630 return;
9631 }
9632 break;
5201c136 9633 case 0x12: /* SQXTUN */
e44a90c5 9634 if (!u) {
5201c136
AB
9635 unallocated_encoding(s);
9636 return;
9637 }
9638 /* fall through */
9639 case 0x14: /* SQXTN, UQXTN */
9640 if (size == 3) {
9641 unallocated_encoding(s);
9642 return;
9643 }
8c6afa6a
PM
9644 if (!fp_access_check(s)) {
9645 return;
9646 }
5201c136
AB
9647 handle_2misc_narrow(s, true, opcode, u, false, size, rn, rd);
9648 return;
8908f4d1
AB
9649 case 0xc ... 0xf:
9650 case 0x16 ... 0x1d:
9651 case 0x1f:
9652 /* Floating point: U, size[1] and opcode indicate operation;
9653 * size[0] indicates single or double precision.
9654 */
9655 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
9656 size = extract32(size, 0, 1) ? 3 : 2;
9657 switch (opcode) {
9658 case 0x2c: /* FCMGT (zero) */
9659 case 0x2d: /* FCMEQ (zero) */
9660 case 0x2e: /* FCMLT (zero) */
9661 case 0x6c: /* FCMGE (zero) */
9662 case 0x6d: /* FCMLE (zero) */
9663 handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd);
9664 return;
10113b69
AB
9665 case 0x1d: /* SCVTF */
9666 case 0x5d: /* UCVTF */
9667 {
9668 bool is_signed = (opcode == 0x1d);
8c6afa6a
PM
9669 if (!fp_access_check(s)) {
9670 return;
9671 }
10113b69
AB
9672 handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size);
9673 return;
9674 }
b6d4443a 9675 case 0x3d: /* FRECPE */
8f0c6758 9676 case 0x3f: /* FRECPX */
c2fb418e 9677 case 0x7d: /* FRSQRTE */
8c6afa6a
PM
9678 if (!fp_access_check(s)) {
9679 return;
9680 }
8f0c6758
AB
9681 handle_2misc_reciprocal(s, opcode, true, u, true, size, rn, rd);
9682 return;
8908f4d1
AB
9683 case 0x1a: /* FCVTNS */
9684 case 0x1b: /* FCVTMS */
8908f4d1
AB
9685 case 0x3a: /* FCVTPS */
9686 case 0x3b: /* FCVTZS */
8908f4d1
AB
9687 case 0x5a: /* FCVTNU */
9688 case 0x5b: /* FCVTMU */
8908f4d1
AB
9689 case 0x7a: /* FCVTPU */
9690 case 0x7b: /* FCVTZU */
04c7c6c2
PM
9691 is_fcvt = true;
9692 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
9693 break;
9694 case 0x1c: /* FCVTAS */
9695 case 0x5c: /* FCVTAU */
9696 /* TIEAWAY doesn't fit in the usual rounding mode encoding */
9697 is_fcvt = true;
9698 rmode = FPROUNDING_TIEAWAY;
9699 break;
04c7c6c2 9700 case 0x56: /* FCVTXN, FCVTXN2 */
5553955e
PM
9701 if (size == 2) {
9702 unallocated_encoding(s);
9703 return;
9704 }
8c6afa6a
PM
9705 if (!fp_access_check(s)) {
9706 return;
9707 }
5553955e
PM
9708 handle_2misc_narrow(s, true, opcode, u, false, size - 1, rn, rd);
9709 return;
8908f4d1
AB
9710 default:
9711 unallocated_encoding(s);
9712 return;
9713 }
9714 break;
effa8e06 9715 default:
09e03735 9716 unallocated_encoding(s);
effa8e06
PM
9717 return;
9718 }
9719
8c6afa6a
PM
9720 if (!fp_access_check(s)) {
9721 return;
9722 }
9723
04c7c6c2
PM
9724 if (is_fcvt) {
9725 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
d81ce0ef 9726 tcg_fpstatus = get_fpstatus_ptr(false);
9b049916 9727 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
04c7c6c2 9728 } else {
f764718d
RH
9729 tcg_rmode = NULL;
9730 tcg_fpstatus = NULL;
04c7c6c2
PM
9731 }
9732
effa8e06
PM
9733 if (size == 3) {
9734 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
9735 TCGv_i64 tcg_rd = tcg_temp_new_i64();
9736
04c7c6c2 9737 handle_2misc_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rmode, tcg_fpstatus);
effa8e06
PM
9738 write_fp_dreg(s, rd, tcg_rd);
9739 tcg_temp_free_i64(tcg_rd);
9740 tcg_temp_free_i64(tcg_rn);
0a79bc87
AB
9741 } else {
9742 TCGv_i32 tcg_rn = tcg_temp_new_i32();
04c7c6c2
PM
9743 TCGv_i32 tcg_rd = tcg_temp_new_i32();
9744
0a79bc87
AB
9745 read_vec_element_i32(s, tcg_rn, rn, 0, size);
9746
04c7c6c2 9747 switch (opcode) {
0a79bc87
AB
9748 case 0x7: /* SQABS, SQNEG */
9749 {
9750 NeonGenOneOpEnvFn *genfn;
9751 static NeonGenOneOpEnvFn * const fns[3][2] = {
9752 { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
9753 { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
9754 { gen_helper_neon_qabs_s32, gen_helper_neon_qneg_s32 },
9755 };
9756 genfn = fns[size][u];
9757 genfn(tcg_rd, cpu_env, tcg_rn);
9758 break;
9759 }
04c7c6c2
PM
9760 case 0x1a: /* FCVTNS */
9761 case 0x1b: /* FCVTMS */
9762 case 0x1c: /* FCVTAS */
9763 case 0x3a: /* FCVTPS */
9764 case 0x3b: /* FCVTZS */
9765 {
9766 TCGv_i32 tcg_shift = tcg_const_i32(0);
9767 gen_helper_vfp_tosls(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus);
9768 tcg_temp_free_i32(tcg_shift);
9769 break;
9770 }
9771 case 0x5a: /* FCVTNU */
9772 case 0x5b: /* FCVTMU */
9773 case 0x5c: /* FCVTAU */
9774 case 0x7a: /* FCVTPU */
9775 case 0x7b: /* FCVTZU */
9776 {
9777 TCGv_i32 tcg_shift = tcg_const_i32(0);
9778 gen_helper_vfp_touls(tcg_rd, tcg_rn, tcg_shift, tcg_fpstatus);
9779 tcg_temp_free_i32(tcg_shift);
9780 break;
9781 }
9782 default:
9783 g_assert_not_reached();
9784 }
9785
9786 write_fp_sreg(s, rd, tcg_rd);
9787 tcg_temp_free_i32(tcg_rd);
9788 tcg_temp_free_i32(tcg_rn);
effa8e06 9789 }
04c7c6c2
PM
9790
9791 if (is_fcvt) {
9b049916 9792 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
04c7c6c2
PM
9793 tcg_temp_free_i32(tcg_rmode);
9794 tcg_temp_free_ptr(tcg_fpstatus);
9795 }
384b26fb
AB
9796}
9797
4d1cef84
AB
9798/* SSHR[RA]/USHR[RA] - Vector shift right (optional rounding/accumulate) */
9799static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
9800 int immh, int immb, int opcode, int rn, int rd)
9801{
9802 int size = 32 - clz32(immh) - 1;
9803 int immhb = immh << 3 | immb;
9804 int shift = 2 * (8 << size) - immhb;
9805 bool accumulate = false;
4d1cef84
AB
9806 int dsize = is_q ? 128 : 64;
9807 int esize = 8 << size;
9808 int elements = dsize/esize;
9809 TCGMemOp memop = size | (is_u ? 0 : MO_SIGN);
9810 TCGv_i64 tcg_rn = new_tmp_a64(s);
9811 TCGv_i64 tcg_rd = new_tmp_a64(s);
9812 TCGv_i64 tcg_round;
cdb45a60 9813 uint64_t round_const;
4d1cef84
AB
9814 int i;
9815
9816 if (extract32(immh, 3, 1) && !is_q) {
9817 unallocated_encoding(s);
9818 return;
9819 }
8dae4697 9820 tcg_debug_assert(size <= 3);
4d1cef84 9821
8c6afa6a
PM
9822 if (!fp_access_check(s)) {
9823 return;
9824 }
9825
4d1cef84
AB
9826 switch (opcode) {
9827 case 0x02: /* SSRA / USRA (accumulate) */
cdb45a60
RH
9828 if (is_u) {
9829 /* Shift count same as element size produces zero to add. */
9830 if (shift == 8 << size) {
9831 goto done;
9832 }
9833 gen_gvec_op2i(s, is_q, rd, rn, shift, &usra_op[size]);
9834 } else {
9835 /* Shift count same as element size produces all sign to add. */
9836 if (shift == 8 << size) {
9837 shift -= 1;
9838 }
9839 gen_gvec_op2i(s, is_q, rd, rn, shift, &ssra_op[size]);
9840 }
9841 return;
9842 case 0x08: /* SRI */
9843 /* Shift count same as element size is valid but does nothing. */
9844 if (shift == 8 << size) {
9845 goto done;
9846 }
9847 gen_gvec_op2i(s, is_q, rd, rn, shift, &sri_op[size]);
9848 return;
9849
9850 case 0x00: /* SSHR / USHR */
9851 if (is_u) {
9852 if (shift == 8 << size) {
9853 /* Shift count the same size as element size produces zero. */
9854 tcg_gen_gvec_dup8i(vec_full_reg_offset(s, rd),
9855 is_q ? 16 : 8, vec_full_reg_size(s), 0);
9856 } else {
9857 gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shri, size);
9858 }
9859 } else {
9860 /* Shift count the same size as element size produces all sign. */
9861 if (shift == 8 << size) {
9862 shift -= 1;
9863 }
9864 gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_sari, size);
9865 }
9866 return;
9867
4d1cef84 9868 case 0x04: /* SRSHR / URSHR (rounding) */
4d1cef84
AB
9869 break;
9870 case 0x06: /* SRSRA / URSRA (accum + rounding) */
cdb45a60 9871 accumulate = true;
37a706ad 9872 break;
cdb45a60
RH
9873 default:
9874 g_assert_not_reached();
4d1cef84
AB
9875 }
9876
cdb45a60
RH
9877 round_const = 1ULL << (shift - 1);
9878 tcg_round = tcg_const_i64(round_const);
4d1cef84
AB
9879
9880 for (i = 0; i < elements; i++) {
9881 read_vec_element(s, tcg_rn, rn, i, memop);
cdb45a60 9882 if (accumulate) {
4d1cef84
AB
9883 read_vec_element(s, tcg_rd, rd, i, memop);
9884 }
9885
cdb45a60
RH
9886 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
9887 accumulate, is_u, size, shift);
4d1cef84
AB
9888
9889 write_vec_element(s, tcg_rd, rd, i, size);
9890 }
cdb45a60 9891 tcg_temp_free_i64(tcg_round);
4d1cef84 9892
cdb45a60 9893 done:
4ff55bcb 9894 clear_vec_high(s, is_q, rd);
cdb45a60 9895}
4d1cef84 9896
4d1cef84
AB
9897/* SHL/SLI - Vector shift left */
9898static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
cdb45a60 9899 int immh, int immb, int opcode, int rn, int rd)
4d1cef84
AB
9900{
9901 int size = 32 - clz32(immh) - 1;
9902 int immhb = immh << 3 | immb;
9903 int shift = immhb - (8 << size);
4d1cef84 9904
f6c98f91
PM
9905 /* Range of size is limited by decode: immh is a non-zero 4 bit field */
9906 assert(size >= 0 && size <= 3);
4d1cef84 9907
f6c98f91 9908 if (extract32(immh, 3, 1) && !is_q) {
4d1cef84
AB
9909 unallocated_encoding(s);
9910 return;
9911 }
9912
8c6afa6a
PM
9913 if (!fp_access_check(s)) {
9914 return;
9915 }
9916
cdb45a60 9917 if (insert) {
f3cd8218 9918 gen_gvec_op2i(s, is_q, rd, rn, shift, &sli_op[size]);
cdb45a60
RH
9919 } else {
9920 gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shli, size);
4d1cef84
AB
9921 }
9922}
9923
9924/* USHLL/SHLL - Vector shift left with widening */
9925static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
9926 int immh, int immb, int opcode, int rn, int rd)
9927{
9928 int size = 32 - clz32(immh) - 1;
9929 int immhb = immh << 3 | immb;
9930 int shift = immhb - (8 << size);
9931 int dsize = 64;
9932 int esize = 8 << size;
9933 int elements = dsize/esize;
9934 TCGv_i64 tcg_rn = new_tmp_a64(s);
9935 TCGv_i64 tcg_rd = new_tmp_a64(s);
9936 int i;
9937
9938 if (size >= 3) {
9939 unallocated_encoding(s);
9940 return;
9941 }
9942
8c6afa6a
PM
9943 if (!fp_access_check(s)) {
9944 return;
9945 }
9946
4d1cef84
AB
9947 /* For the LL variants the store is larger than the load,
9948 * so if rd == rn we would overwrite parts of our input.
9949 * So load everything right now and use shifts in the main loop.
9950 */
9951 read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64);
9952
9953 for (i = 0; i < elements; i++) {
9954 tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize);
9955 ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0);
9956 tcg_gen_shli_i64(tcg_rd, tcg_rd, shift);
9957 write_vec_element(s, tcg_rd, rd, i, size + 1);
9958 }
9959}
9960
c1b876b2
AB
9961/* SHRN/RSHRN - Shift right with narrowing (and potential rounding) */
9962static void handle_vec_simd_shrn(DisasContext *s, bool is_q,
9963 int immh, int immb, int opcode, int rn, int rd)
9964{
9965 int immhb = immh << 3 | immb;
9966 int size = 32 - clz32(immh) - 1;
9967 int dsize = 64;
9968 int esize = 8 << size;
9969 int elements = dsize/esize;
9970 int shift = (2 * esize) - immhb;
9971 bool round = extract32(opcode, 0, 1);
9972 TCGv_i64 tcg_rn, tcg_rd, tcg_final;
9973 TCGv_i64 tcg_round;
9974 int i;
9975
9976 if (extract32(immh, 3, 1)) {
9977 unallocated_encoding(s);
9978 return;
9979 }
9980
8c6afa6a
PM
9981 if (!fp_access_check(s)) {
9982 return;
9983 }
9984
c1b876b2
AB
9985 tcg_rn = tcg_temp_new_i64();
9986 tcg_rd = tcg_temp_new_i64();
9987 tcg_final = tcg_temp_new_i64();
9988 read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64);
9989
9990 if (round) {
9991 uint64_t round_const = 1ULL << (shift - 1);
9992 tcg_round = tcg_const_i64(round_const);
9993 } else {
f764718d 9994 tcg_round = NULL;
c1b876b2
AB
9995 }
9996
9997 for (i = 0; i < elements; i++) {
9998 read_vec_element(s, tcg_rn, rn, i, size+1);
9999 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
10000 false, true, size+1, shift);
10001
10002 tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
10003 }
10004
10005 if (!is_q) {
c1b876b2
AB
10006 write_vec_element(s, tcg_final, rd, 0, MO_64);
10007 } else {
10008 write_vec_element(s, tcg_final, rd, 1, MO_64);
10009 }
c1b876b2
AB
10010 if (round) {
10011 tcg_temp_free_i64(tcg_round);
10012 }
10013 tcg_temp_free_i64(tcg_rn);
10014 tcg_temp_free_i64(tcg_rd);
10015 tcg_temp_free_i64(tcg_final);
4ff55bcb
RH
10016
10017 clear_vec_high(s, is_q, rd);
c1b876b2
AB
10018}
10019
10020
4ce31af4 10021/* AdvSIMD shift by immediate
384b26fb
AB
10022 * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
10023 * +---+---+---+-------------+------+------+--------+---+------+------+
10024 * | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
10025 * +---+---+---+-------------+------+------+--------+---+------+------+
10026 */
10027static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
10028{
4d1cef84
AB
10029 int rd = extract32(insn, 0, 5);
10030 int rn = extract32(insn, 5, 5);
10031 int opcode = extract32(insn, 11, 5);
10032 int immb = extract32(insn, 16, 3);
10033 int immh = extract32(insn, 19, 4);
10034 bool is_u = extract32(insn, 29, 1);
10035 bool is_q = extract32(insn, 30, 1);
10036
10037 switch (opcode) {
37a706ad
PM
10038 case 0x08: /* SRI */
10039 if (!is_u) {
10040 unallocated_encoding(s);
10041 return;
10042 }
10043 /* fall through */
4d1cef84
AB
10044 case 0x00: /* SSHR / USHR */
10045 case 0x02: /* SSRA / USRA (accumulate) */
10046 case 0x04: /* SRSHR / URSHR (rounding) */
10047 case 0x06: /* SRSRA / URSRA (accum + rounding) */
10048 handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd);
10049 break;
10050 case 0x0a: /* SHL / SLI */
10051 handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd);
10052 break;
c1b876b2
AB
10053 case 0x10: /* SHRN */
10054 case 0x11: /* RSHRN / SQRSHRUN */
10055 if (is_u) {
10056 handle_vec_simd_sqshrn(s, false, is_q, false, true, immh, immb,
10057 opcode, rn, rd);
10058 } else {
10059 handle_vec_simd_shrn(s, is_q, immh, immb, opcode, rn, rd);
10060 }
10061 break;
10062 case 0x12: /* SQSHRN / UQSHRN */
10063 case 0x13: /* SQRSHRN / UQRSHRN */
10064 handle_vec_simd_sqshrn(s, false, is_q, is_u, is_u, immh, immb,
10065 opcode, rn, rd);
10066 break;
4d1cef84
AB
10067 case 0x14: /* SSHLL / USHLL */
10068 handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd);
10069 break;
10113b69
AB
10070 case 0x1c: /* SCVTF / UCVTF */
10071 handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
10072 opcode, rn, rd);
10073 break;
a566da1b 10074 case 0xc: /* SQSHLU */
a847f32c
PM
10075 if (!is_u) {
10076 unallocated_encoding(s);
10077 return;
10078 }
10079 handle_simd_qshl(s, false, is_q, false, true, immh, immb, rn, rd);
10080 break;
a566da1b 10081 case 0xe: /* SQSHL, UQSHL */
a847f32c
PM
10082 handle_simd_qshl(s, false, is_q, is_u, is_u, immh, immb, rn, rd);
10083 break;
10113b69 10084 case 0x1f: /* FCVTZS/ FCVTZU */
2ed3ea11 10085 handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd);
10113b69 10086 return;
4d1cef84 10087 default:
a566da1b 10088 unallocated_encoding(s);
4d1cef84
AB
10089 return;
10090 }
384b26fb
AB
10091}
10092
70d7f984
PM
10093/* Generate code to do a "long" addition or subtraction, ie one done in
10094 * TCGv_i64 on vector lanes twice the width specified by size.
10095 */
10096static void gen_neon_addl(int size, bool is_sub, TCGv_i64 tcg_res,
10097 TCGv_i64 tcg_op1, TCGv_i64 tcg_op2)
10098{
10099 static NeonGenTwo64OpFn * const fns[3][2] = {
10100 { gen_helper_neon_addl_u16, gen_helper_neon_subl_u16 },
10101 { gen_helper_neon_addl_u32, gen_helper_neon_subl_u32 },
10102 { tcg_gen_add_i64, tcg_gen_sub_i64 },
10103 };
10104 NeonGenTwo64OpFn *genfn;
10105 assert(size < 3);
10106
10107 genfn = fns[size][is_sub];
10108 genfn(tcg_res, tcg_op1, tcg_op2);
10109}
10110
a08582f4
PM
10111static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
10112 int opcode, int rd, int rn, int rm)
10113{
10114 /* 3-reg-different widening insns: 64 x 64 -> 128 */
10115 TCGv_i64 tcg_res[2];
10116 int pass, accop;
10117
10118 tcg_res[0] = tcg_temp_new_i64();
10119 tcg_res[1] = tcg_temp_new_i64();
10120
10121 /* Does this op do an adding accumulate, a subtracting accumulate,
10122 * or no accumulate at all?
10123 */
10124 switch (opcode) {
10125 case 5:
10126 case 8:
10127 case 9:
10128 accop = 1;
10129 break;
10130 case 10:
10131 case 11:
10132 accop = -1;
10133 break;
10134 default:
10135 accop = 0;
10136 break;
10137 }
10138
10139 if (accop != 0) {
10140 read_vec_element(s, tcg_res[0], rd, 0, MO_64);
10141 read_vec_element(s, tcg_res[1], rd, 1, MO_64);
10142 }
10143
10144 /* size == 2 means two 32x32->64 operations; this is worth special
10145 * casing because we can generally handle it inline.
10146 */
10147 if (size == 2) {
10148 for (pass = 0; pass < 2; pass++) {
10149 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10150 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10151 TCGv_i64 tcg_passres;
10152 TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
10153
10154 int elt = pass + is_q * 2;
10155
10156 read_vec_element(s, tcg_op1, rn, elt, memop);
10157 read_vec_element(s, tcg_op2, rm, elt, memop);
10158
10159 if (accop == 0) {
10160 tcg_passres = tcg_res[pass];
10161 } else {
10162 tcg_passres = tcg_temp_new_i64();
10163 }
10164
10165 switch (opcode) {
70d7f984
PM
10166 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
10167 tcg_gen_add_i64(tcg_passres, tcg_op1, tcg_op2);
10168 break;
10169 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
10170 tcg_gen_sub_i64(tcg_passres, tcg_op1, tcg_op2);
10171 break;
0ae39320
PM
10172 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
10173 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
10174 {
10175 TCGv_i64 tcg_tmp1 = tcg_temp_new_i64();
10176 TCGv_i64 tcg_tmp2 = tcg_temp_new_i64();
10177
10178 tcg_gen_sub_i64(tcg_tmp1, tcg_op1, tcg_op2);
10179 tcg_gen_sub_i64(tcg_tmp2, tcg_op2, tcg_op1);
10180 tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
10181 tcg_passres,
10182 tcg_op1, tcg_op2, tcg_tmp1, tcg_tmp2);
10183 tcg_temp_free_i64(tcg_tmp1);
10184 tcg_temp_free_i64(tcg_tmp2);
10185 break;
10186 }
a08582f4
PM
10187 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
10188 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
10189 case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
10190 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
10191 break;
70d7f984
PM
10192 case 9: /* SQDMLAL, SQDMLAL2 */
10193 case 11: /* SQDMLSL, SQDMLSL2 */
10194 case 13: /* SQDMULL, SQDMULL2 */
10195 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
10196 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
10197 tcg_passres, tcg_passres);
10198 break;
a08582f4
PM
10199 default:
10200 g_assert_not_reached();
10201 }
10202
70d7f984
PM
10203 if (opcode == 9 || opcode == 11) {
10204 /* saturating accumulate ops */
10205 if (accop < 0) {
10206 tcg_gen_neg_i64(tcg_passres, tcg_passres);
10207 }
10208 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
10209 tcg_res[pass], tcg_passres);
10210 } else if (accop > 0) {
a08582f4 10211 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
a08582f4
PM
10212 } else if (accop < 0) {
10213 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
70d7f984
PM
10214 }
10215
10216 if (accop != 0) {
a08582f4
PM
10217 tcg_temp_free_i64(tcg_passres);
10218 }
10219
10220 tcg_temp_free_i64(tcg_op1);
10221 tcg_temp_free_i64(tcg_op2);
10222 }
10223 } else {
10224 /* size 0 or 1, generally helper functions */
10225 for (pass = 0; pass < 2; pass++) {
10226 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
10227 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10228 TCGv_i64 tcg_passres;
10229 int elt = pass + is_q * 2;
10230
10231 read_vec_element_i32(s, tcg_op1, rn, elt, MO_32);
10232 read_vec_element_i32(s, tcg_op2, rm, elt, MO_32);
10233
10234 if (accop == 0) {
10235 tcg_passres = tcg_res[pass];
10236 } else {
10237 tcg_passres = tcg_temp_new_i64();
10238 }
10239
10240 switch (opcode) {
70d7f984
PM
10241 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
10242 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
10243 {
10244 TCGv_i64 tcg_op2_64 = tcg_temp_new_i64();
10245 static NeonGenWidenFn * const widenfns[2][2] = {
10246 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
10247 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
10248 };
10249 NeonGenWidenFn *widenfn = widenfns[size][is_u];
10250
10251 widenfn(tcg_op2_64, tcg_op2);
10252 widenfn(tcg_passres, tcg_op1);
10253 gen_neon_addl(size, (opcode == 2), tcg_passres,
10254 tcg_passres, tcg_op2_64);
10255 tcg_temp_free_i64(tcg_op2_64);
10256 break;
10257 }
0ae39320
PM
10258 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
10259 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
10260 if (size == 0) {
10261 if (is_u) {
10262 gen_helper_neon_abdl_u16(tcg_passres, tcg_op1, tcg_op2);
10263 } else {
10264 gen_helper_neon_abdl_s16(tcg_passres, tcg_op1, tcg_op2);
10265 }
10266 } else {
10267 if (is_u) {
10268 gen_helper_neon_abdl_u32(tcg_passres, tcg_op1, tcg_op2);
10269 } else {
10270 gen_helper_neon_abdl_s32(tcg_passres, tcg_op1, tcg_op2);
10271 }
10272 }
10273 break;
a08582f4
PM
10274 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
10275 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
10276 case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
10277 if (size == 0) {
10278 if (is_u) {
10279 gen_helper_neon_mull_u8(tcg_passres, tcg_op1, tcg_op2);
10280 } else {
10281 gen_helper_neon_mull_s8(tcg_passres, tcg_op1, tcg_op2);
10282 }
10283 } else {
10284 if (is_u) {
10285 gen_helper_neon_mull_u16(tcg_passres, tcg_op1, tcg_op2);
10286 } else {
10287 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
10288 }
10289 }
10290 break;
70d7f984
PM
10291 case 9: /* SQDMLAL, SQDMLAL2 */
10292 case 11: /* SQDMLSL, SQDMLSL2 */
10293 case 13: /* SQDMULL, SQDMULL2 */
10294 assert(size == 1);
10295 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
10296 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
10297 tcg_passres, tcg_passres);
10298 break;
a984e42c
PM
10299 case 14: /* PMULL */
10300 assert(size == 0);
10301 gen_helper_neon_mull_p8(tcg_passres, tcg_op1, tcg_op2);
10302 break;
a08582f4
PM
10303 default:
10304 g_assert_not_reached();
10305 }
10306 tcg_temp_free_i32(tcg_op1);
10307 tcg_temp_free_i32(tcg_op2);
10308
70d7f984
PM
10309 if (accop != 0) {
10310 if (opcode == 9 || opcode == 11) {
10311 /* saturating accumulate ops */
10312 if (accop < 0) {
10313 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
10314 }
10315 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
10316 tcg_res[pass],
10317 tcg_passres);
a08582f4 10318 } else {
70d7f984
PM
10319 gen_neon_addl(size, (accop < 0), tcg_res[pass],
10320 tcg_res[pass], tcg_passres);
a08582f4
PM
10321 }
10322 tcg_temp_free_i64(tcg_passres);
10323 }
10324 }
10325 }
10326
10327 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
10328 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
10329 tcg_temp_free_i64(tcg_res[0]);
10330 tcg_temp_free_i64(tcg_res[1]);
10331}
10332
dfc15c7c
PM
10333static void handle_3rd_wide(DisasContext *s, int is_q, int is_u, int size,
10334 int opcode, int rd, int rn, int rm)
10335{
10336 TCGv_i64 tcg_res[2];
10337 int part = is_q ? 2 : 0;
10338 int pass;
10339
10340 for (pass = 0; pass < 2; pass++) {
10341 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10342 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10343 TCGv_i64 tcg_op2_wide = tcg_temp_new_i64();
10344 static NeonGenWidenFn * const widenfns[3][2] = {
10345 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
10346 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
10347 { tcg_gen_ext_i32_i64, tcg_gen_extu_i32_i64 },
10348 };
10349 NeonGenWidenFn *widenfn = widenfns[size][is_u];
10350
10351 read_vec_element(s, tcg_op1, rn, pass, MO_64);
10352 read_vec_element_i32(s, tcg_op2, rm, part + pass, MO_32);
10353 widenfn(tcg_op2_wide, tcg_op2);
10354 tcg_temp_free_i32(tcg_op2);
10355 tcg_res[pass] = tcg_temp_new_i64();
10356 gen_neon_addl(size, (opcode == 3),
10357 tcg_res[pass], tcg_op1, tcg_op2_wide);
10358 tcg_temp_free_i64(tcg_op1);
10359 tcg_temp_free_i64(tcg_op2_wide);
10360 }
10361
10362 for (pass = 0; pass < 2; pass++) {
10363 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
10364 tcg_temp_free_i64(tcg_res[pass]);
10365 }
10366}
10367
e4b998d4
PM
10368static void do_narrow_round_high_u32(TCGv_i32 res, TCGv_i64 in)
10369{
10370 tcg_gen_addi_i64(in, in, 1U << 31);
7cb36e18 10371 tcg_gen_extrh_i64_i32(res, in);
e4b998d4
PM
10372}
10373
10374static void handle_3rd_narrowing(DisasContext *s, int is_q, int is_u, int size,
10375 int opcode, int rd, int rn, int rm)
10376{
10377 TCGv_i32 tcg_res[2];
10378 int part = is_q ? 2 : 0;
10379 int pass;
10380
10381 for (pass = 0; pass < 2; pass++) {
10382 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10383 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10384 TCGv_i64 tcg_wideres = tcg_temp_new_i64();
10385 static NeonGenNarrowFn * const narrowfns[3][2] = {
10386 { gen_helper_neon_narrow_high_u8,
10387 gen_helper_neon_narrow_round_high_u8 },
10388 { gen_helper_neon_narrow_high_u16,
10389 gen_helper_neon_narrow_round_high_u16 },
7cb36e18 10390 { tcg_gen_extrh_i64_i32, do_narrow_round_high_u32 },
e4b998d4
PM
10391 };
10392 NeonGenNarrowFn *gennarrow = narrowfns[size][is_u];
10393
10394 read_vec_element(s, tcg_op1, rn, pass, MO_64);
10395 read_vec_element(s, tcg_op2, rm, pass, MO_64);
10396
10397 gen_neon_addl(size, (opcode == 6), tcg_wideres, tcg_op1, tcg_op2);
10398
10399 tcg_temp_free_i64(tcg_op1);
10400 tcg_temp_free_i64(tcg_op2);
10401
10402 tcg_res[pass] = tcg_temp_new_i32();
10403 gennarrow(tcg_res[pass], tcg_wideres);
10404 tcg_temp_free_i64(tcg_wideres);
10405 }
10406
10407 for (pass = 0; pass < 2; pass++) {
10408 write_vec_element_i32(s, tcg_res[pass], rd, pass + part, MO_32);
10409 tcg_temp_free_i32(tcg_res[pass]);
10410 }
4ff55bcb 10411 clear_vec_high(s, is_q, rd);
e4b998d4
PM
10412}
10413
a984e42c
PM
10414static void handle_pmull_64(DisasContext *s, int is_q, int rd, int rn, int rm)
10415{
10416 /* PMULL of 64 x 64 -> 128 is an odd special case because it
10417 * is the only three-reg-diff instruction which produces a
10418 * 128-bit wide result from a single operation. However since
10419 * it's possible to calculate the two halves more or less
10420 * separately we just use two helper calls.
10421 */
10422 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10423 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10424 TCGv_i64 tcg_res = tcg_temp_new_i64();
10425
10426 read_vec_element(s, tcg_op1, rn, is_q, MO_64);
10427 read_vec_element(s, tcg_op2, rm, is_q, MO_64);
10428 gen_helper_neon_pmull_64_lo(tcg_res, tcg_op1, tcg_op2);
10429 write_vec_element(s, tcg_res, rd, 0, MO_64);
10430 gen_helper_neon_pmull_64_hi(tcg_res, tcg_op1, tcg_op2);
10431 write_vec_element(s, tcg_res, rd, 1, MO_64);
10432
10433 tcg_temp_free_i64(tcg_op1);
10434 tcg_temp_free_i64(tcg_op2);
10435 tcg_temp_free_i64(tcg_res);
10436}
10437
4ce31af4 10438/* AdvSIMD three different
384b26fb
AB
10439 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
10440 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
10441 * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
10442 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
10443 */
10444static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
10445{
a08582f4
PM
10446 /* Instructions in this group fall into three basic classes
10447 * (in each case with the operation working on each element in
10448 * the input vectors):
10449 * (1) widening 64 x 64 -> 128 (with possibly Vd as an extra
10450 * 128 bit input)
10451 * (2) wide 64 x 128 -> 128
10452 * (3) narrowing 128 x 128 -> 64
10453 * Here we do initial decode, catch unallocated cases and
10454 * dispatch to separate functions for each class.
10455 */
10456 int is_q = extract32(insn, 30, 1);
10457 int is_u = extract32(insn, 29, 1);
10458 int size = extract32(insn, 22, 2);
10459 int opcode = extract32(insn, 12, 4);
10460 int rm = extract32(insn, 16, 5);
10461 int rn = extract32(insn, 5, 5);
10462 int rd = extract32(insn, 0, 5);
10463
10464 switch (opcode) {
10465 case 1: /* SADDW, SADDW2, UADDW, UADDW2 */
10466 case 3: /* SSUBW, SSUBW2, USUBW, USUBW2 */
10467 /* 64 x 128 -> 128 */
dfc15c7c
PM
10468 if (size == 3) {
10469 unallocated_encoding(s);
10470 return;
10471 }
8c6afa6a
PM
10472 if (!fp_access_check(s)) {
10473 return;
10474 }
dfc15c7c 10475 handle_3rd_wide(s, is_q, is_u, size, opcode, rd, rn, rm);
a08582f4
PM
10476 break;
10477 case 4: /* ADDHN, ADDHN2, RADDHN, RADDHN2 */
10478 case 6: /* SUBHN, SUBHN2, RSUBHN, RSUBHN2 */
10479 /* 128 x 128 -> 64 */
e4b998d4
PM
10480 if (size == 3) {
10481 unallocated_encoding(s);
10482 return;
10483 }
8c6afa6a
PM
10484 if (!fp_access_check(s)) {
10485 return;
10486 }
e4b998d4 10487 handle_3rd_narrowing(s, is_q, is_u, size, opcode, rd, rn, rm);
a08582f4 10488 break;
70d7f984
PM
10489 case 14: /* PMULL, PMULL2 */
10490 if (is_u || size == 1 || size == 2) {
10491 unallocated_encoding(s);
10492 return;
10493 }
a984e42c 10494 if (size == 3) {
962fcbf2 10495 if (!dc_isar_feature(aa64_pmull, s)) {
a984e42c
PM
10496 unallocated_encoding(s);
10497 return;
10498 }
8c6afa6a
PM
10499 if (!fp_access_check(s)) {
10500 return;
10501 }
a984e42c
PM
10502 handle_pmull_64(s, is_q, rd, rn, rm);
10503 return;
10504 }
10505 goto is_widening;
13caf1fd
PM
10506 case 9: /* SQDMLAL, SQDMLAL2 */
10507 case 11: /* SQDMLSL, SQDMLSL2 */
10508 case 13: /* SQDMULL, SQDMULL2 */
70d7f984 10509 if (is_u || size == 0) {
a08582f4
PM
10510 unallocated_encoding(s);
10511 return;
10512 }
10513 /* fall through */
13caf1fd
PM
10514 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
10515 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
13caf1fd
PM
10516 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
10517 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
10518 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
10519 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
10520 case 12: /* SMULL, SMULL2, UMULL, UMULL2 */
a08582f4
PM
10521 /* 64 x 64 -> 128 */
10522 if (size == 3) {
10523 unallocated_encoding(s);
10524 return;
10525 }
a984e42c 10526 is_widening:
8c6afa6a
PM
10527 if (!fp_access_check(s)) {
10528 return;
10529 }
10530
a08582f4
PM
10531 handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
10532 break;
10533 default:
10534 /* opcode 15 not allocated */
10535 unallocated_encoding(s);
10536 break;
10537 }
384b26fb
AB
10538}
10539
e1cea114
PM
10540/* Logic op (opcode == 3) subgroup of C3.6.16. */
10541static void disas_simd_3same_logic(DisasContext *s, uint32_t insn)
10542{
956d272e
PM
10543 int rd = extract32(insn, 0, 5);
10544 int rn = extract32(insn, 5, 5);
10545 int rm = extract32(insn, 16, 5);
10546 int size = extract32(insn, 22, 2);
10547 bool is_u = extract32(insn, 29, 1);
10548 bool is_q = extract32(insn, 30, 1);
956d272e 10549
8c6afa6a
PM
10550 if (!fp_access_check(s)) {
10551 return;
10552 }
10553
bc48092f
RH
10554 switch (size + 4 * is_u) {
10555 case 0: /* AND */
10556 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_and, 0);
10557 return;
10558 case 1: /* BIC */
10559 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_andc, 0);
10560 return;
10561 case 2: /* ORR */
377ef731
RH
10562 if (rn == rm) { /* MOV */
10563 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_mov, 0);
10564 } else {
10565 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_or, 0);
10566 }
bc48092f
RH
10567 return;
10568 case 3: /* ORN */
10569 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_orc, 0);
10570 return;
10571 case 4: /* EOR */
10572 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_xor, 0);
10573 return;
956d272e 10574
bc48092f
RH
10575 case 5: /* BSL bitwise select */
10576 gen_gvec_op3(s, is_q, rd, rn, rm, &bsl_op);
10577 return;
10578 case 6: /* BIT, bitwise insert if true */
10579 gen_gvec_op3(s, is_q, rd, rn, rm, &bit_op);
10580 return;
10581 case 7: /* BIF, bitwise insert if false */
10582 gen_gvec_op3(s, is_q, rd, rn, rm, &bif_op);
10583 return;
956d272e 10584
bc48092f
RH
10585 default:
10586 g_assert_not_reached();
956d272e 10587 }
e1cea114
PM
10588}
10589
bc242f9b
AB
10590/* Pairwise op subgroup of C3.6.16.
10591 *
10592 * This is called directly or via the handle_3same_float for float pairwise
10593 * operations where the opcode and size are calculated differently.
10594 */
10595static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode,
10596 int size, int rn, int rm, int rd)
e1cea114 10597{
bc242f9b 10598 TCGv_ptr fpst;
0173a005
PM
10599 int pass;
10600
bc242f9b
AB
10601 /* Floating point operations need fpst */
10602 if (opcode >= 0x58) {
d81ce0ef 10603 fpst = get_fpstatus_ptr(false);
bc242f9b 10604 } else {
f764718d 10605 fpst = NULL;
0173a005
PM
10606 }
10607
8c6afa6a
PM
10608 if (!fp_access_check(s)) {
10609 return;
10610 }
10611
0173a005
PM
10612 /* These operations work on the concatenated rm:rn, with each pair of
10613 * adjacent elements being operated on to produce an element in the result.
10614 */
10615 if (size == 3) {
10616 TCGv_i64 tcg_res[2];
10617
10618 for (pass = 0; pass < 2; pass++) {
10619 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10620 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10621 int passreg = (pass == 0) ? rn : rm;
10622
10623 read_vec_element(s, tcg_op1, passreg, 0, MO_64);
10624 read_vec_element(s, tcg_op2, passreg, 1, MO_64);
10625 tcg_res[pass] = tcg_temp_new_i64();
10626
bc242f9b
AB
10627 switch (opcode) {
10628 case 0x17: /* ADDP */
10629 tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
10630 break;
10631 case 0x58: /* FMAXNMP */
10632 gen_helper_vfp_maxnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10633 break;
10634 case 0x5a: /* FADDP */
10635 gen_helper_vfp_addd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10636 break;
10637 case 0x5e: /* FMAXP */
10638 gen_helper_vfp_maxd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10639 break;
10640 case 0x78: /* FMINNMP */
10641 gen_helper_vfp_minnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10642 break;
10643 case 0x7e: /* FMINP */
10644 gen_helper_vfp_mind(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10645 break;
10646 default:
10647 g_assert_not_reached();
10648 }
0173a005
PM
10649
10650 tcg_temp_free_i64(tcg_op1);
10651 tcg_temp_free_i64(tcg_op2);
10652 }
10653
10654 for (pass = 0; pass < 2; pass++) {
10655 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
10656 tcg_temp_free_i64(tcg_res[pass]);
10657 }
10658 } else {
10659 int maxpass = is_q ? 4 : 2;
10660 TCGv_i32 tcg_res[4];
10661
10662 for (pass = 0; pass < maxpass; pass++) {
10663 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
10664 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
bc242f9b 10665 NeonGenTwoOpFn *genfn = NULL;
0173a005
PM
10666 int passreg = pass < (maxpass / 2) ? rn : rm;
10667 int passelt = (is_q && (pass & 1)) ? 2 : 0;
10668
10669 read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_32);
10670 read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_32);
10671 tcg_res[pass] = tcg_temp_new_i32();
10672
10673 switch (opcode) {
10674 case 0x17: /* ADDP */
10675 {
10676 static NeonGenTwoOpFn * const fns[3] = {
10677 gen_helper_neon_padd_u8,
10678 gen_helper_neon_padd_u16,
10679 tcg_gen_add_i32,
10680 };
10681 genfn = fns[size];
10682 break;
10683 }
10684 case 0x14: /* SMAXP, UMAXP */
10685 {
10686 static NeonGenTwoOpFn * const fns[3][2] = {
10687 { gen_helper_neon_pmax_s8, gen_helper_neon_pmax_u8 },
10688 { gen_helper_neon_pmax_s16, gen_helper_neon_pmax_u16 },
ecb8ab8d 10689 { tcg_gen_smax_i32, tcg_gen_umax_i32 },
0173a005
PM
10690 };
10691 genfn = fns[size][u];
10692 break;
10693 }
10694 case 0x15: /* SMINP, UMINP */
10695 {
10696 static NeonGenTwoOpFn * const fns[3][2] = {
10697 { gen_helper_neon_pmin_s8, gen_helper_neon_pmin_u8 },
10698 { gen_helper_neon_pmin_s16, gen_helper_neon_pmin_u16 },
ecb8ab8d 10699 { tcg_gen_smin_i32, tcg_gen_umin_i32 },
0173a005
PM
10700 };
10701 genfn = fns[size][u];
10702 break;
10703 }
bc242f9b
AB
10704 /* The FP operations are all on single floats (32 bit) */
10705 case 0x58: /* FMAXNMP */
10706 gen_helper_vfp_maxnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10707 break;
10708 case 0x5a: /* FADDP */
10709 gen_helper_vfp_adds(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10710 break;
10711 case 0x5e: /* FMAXP */
10712 gen_helper_vfp_maxs(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10713 break;
10714 case 0x78: /* FMINNMP */
10715 gen_helper_vfp_minnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10716 break;
10717 case 0x7e: /* FMINP */
10718 gen_helper_vfp_mins(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10719 break;
0173a005
PM
10720 default:
10721 g_assert_not_reached();
10722 }
10723
bc242f9b
AB
10724 /* FP ops called directly, otherwise call now */
10725 if (genfn) {
10726 genfn(tcg_res[pass], tcg_op1, tcg_op2);
10727 }
0173a005
PM
10728
10729 tcg_temp_free_i32(tcg_op1);
10730 tcg_temp_free_i32(tcg_op2);
10731 }
10732
10733 for (pass = 0; pass < maxpass; pass++) {
10734 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
10735 tcg_temp_free_i32(tcg_res[pass]);
10736 }
4ff55bcb 10737 clear_vec_high(s, is_q, rd);
0173a005 10738 }
bc242f9b 10739
f764718d 10740 if (fpst) {
bc242f9b
AB
10741 tcg_temp_free_ptr(fpst);
10742 }
e1cea114
PM
10743}
10744
10745/* Floating point op subgroup of C3.6.16. */
10746static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
10747{
845ea09a
PM
10748 /* For floating point ops, the U, size[1] and opcode bits
10749 * together indicate the operation. size[0] indicates single
10750 * or double.
10751 */
10752 int fpopcode = extract32(insn, 11, 5)
10753 | (extract32(insn, 23, 1) << 5)
10754 | (extract32(insn, 29, 1) << 6);
10755 int is_q = extract32(insn, 30, 1);
10756 int size = extract32(insn, 22, 1);
10757 int rm = extract32(insn, 16, 5);
10758 int rn = extract32(insn, 5, 5);
10759 int rd = extract32(insn, 0, 5);
10760
10761 int datasize = is_q ? 128 : 64;
10762 int esize = 32 << size;
10763 int elements = datasize / esize;
10764
10765 if (size == 1 && !is_q) {
10766 unallocated_encoding(s);
10767 return;
10768 }
10769
10770 switch (fpopcode) {
10771 case 0x58: /* FMAXNMP */
10772 case 0x5a: /* FADDP */
10773 case 0x5e: /* FMAXP */
10774 case 0x78: /* FMINNMP */
10775 case 0x7e: /* FMINP */
bc242f9b
AB
10776 if (size && !is_q) {
10777 unallocated_encoding(s);
10778 return;
10779 }
10780 handle_simd_3same_pair(s, is_q, 0, fpopcode, size ? MO_64 : MO_32,
10781 rn, rm, rd);
845ea09a
PM
10782 return;
10783 case 0x1b: /* FMULX */
845ea09a
PM
10784 case 0x1f: /* FRECPS */
10785 case 0x3f: /* FRSQRTS */
845ea09a 10786 case 0x5d: /* FACGE */
845ea09a
PM
10787 case 0x7d: /* FACGT */
10788 case 0x19: /* FMLA */
10789 case 0x39: /* FMLS */
845ea09a
PM
10790 case 0x18: /* FMAXNM */
10791 case 0x1a: /* FADD */
8908f4d1 10792 case 0x1c: /* FCMEQ */
845ea09a
PM
10793 case 0x1e: /* FMAX */
10794 case 0x38: /* FMINNM */
10795 case 0x3a: /* FSUB */
10796 case 0x3e: /* FMIN */
10797 case 0x5b: /* FMUL */
8908f4d1 10798 case 0x5c: /* FCMGE */
845ea09a
PM
10799 case 0x5f: /* FDIV */
10800 case 0x7a: /* FABD */
8908f4d1 10801 case 0x7c: /* FCMGT */
8c6afa6a
PM
10802 if (!fp_access_check(s)) {
10803 return;
10804 }
10805
845ea09a
PM
10806 handle_3same_float(s, size, elements, fpopcode, rd, rn, rm);
10807 return;
10808 default:
10809 unallocated_encoding(s);
10810 return;
10811 }
e1cea114
PM
10812}
10813
10814/* Integer op subgroup of C3.6.16. */
10815static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
10816{
1f8a73af
PM
10817 int is_q = extract32(insn, 30, 1);
10818 int u = extract32(insn, 29, 1);
10819 int size = extract32(insn, 22, 2);
10820 int opcode = extract32(insn, 11, 5);
10821 int rm = extract32(insn, 16, 5);
10822 int rn = extract32(insn, 5, 5);
10823 int rd = extract32(insn, 0, 5);
10824 int pass;
79d61de6 10825 TCGCond cond;
1f8a73af
PM
10826
10827 switch (opcode) {
10828 case 0x13: /* MUL, PMUL */
10829 if (u && size != 0) {
10830 unallocated_encoding(s);
10831 return;
10832 }
10833 /* fall through */
10834 case 0x0: /* SHADD, UHADD */
10835 case 0x2: /* SRHADD, URHADD */
10836 case 0x4: /* SHSUB, UHSUB */
10837 case 0xc: /* SMAX, UMAX */
10838 case 0xd: /* SMIN, UMIN */
10839 case 0xe: /* SABD, UABD */
10840 case 0xf: /* SABA, UABA */
10841 case 0x12: /* MLA, MLS */
10842 if (size == 3) {
10843 unallocated_encoding(s);
10844 return;
10845 }
8b12a0cf 10846 break;
1f8a73af
PM
10847 case 0x16: /* SQDMULH, SQRDMULH */
10848 if (size == 0 || size == 3) {
10849 unallocated_encoding(s);
10850 return;
10851 }
8b12a0cf 10852 break;
1f8a73af
PM
10853 default:
10854 if (size == 3 && !is_q) {
10855 unallocated_encoding(s);
10856 return;
10857 }
10858 break;
10859 }
10860
8c6afa6a
PM
10861 if (!fp_access_check(s)) {
10862 return;
10863 }
10864
bc48092f
RH
10865 switch (opcode) {
10866 case 0x10: /* ADD, SUB */
10867 if (u) {
10868 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_sub, size);
10869 } else {
10870 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_add, size);
10871 }
10872 return;
0c7c55c4
RH
10873 case 0x13: /* MUL, PMUL */
10874 if (!u) { /* MUL */
10875 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_mul, size);
10876 return;
10877 }
10878 break;
10879 case 0x12: /* MLA, MLS */
10880 if (u) {
10881 gen_gvec_op3(s, is_q, rd, rn, rm, &mls_op[size]);
10882 } else {
10883 gen_gvec_op3(s, is_q, rd, rn, rm, &mla_op[size]);
10884 }
10885 return;
79d61de6
RH
10886 case 0x11:
10887 if (!u) { /* CMTST */
10888 gen_gvec_op3(s, is_q, rd, rn, rm, &cmtst_op[size]);
10889 return;
10890 }
10891 /* else CMEQ */
10892 cond = TCG_COND_EQ;
10893 goto do_gvec_cmp;
10894 case 0x06: /* CMGT, CMHI */
10895 cond = u ? TCG_COND_GTU : TCG_COND_GT;
10896 goto do_gvec_cmp;
10897 case 0x07: /* CMGE, CMHS */
10898 cond = u ? TCG_COND_GEU : TCG_COND_GE;
10899 do_gvec_cmp:
10900 tcg_gen_gvec_cmp(cond, size, vec_full_reg_offset(s, rd),
10901 vec_full_reg_offset(s, rn),
10902 vec_full_reg_offset(s, rm),
10903 is_q ? 16 : 8, vec_full_reg_size(s));
10904 return;
bc48092f
RH
10905 }
10906
1f8a73af 10907 if (size == 3) {
220ad4ca
PM
10908 assert(is_q);
10909 for (pass = 0; pass < 2; pass++) {
1f8a73af
PM
10910 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10911 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10912 TCGv_i64 tcg_res = tcg_temp_new_i64();
10913
10914 read_vec_element(s, tcg_op1, rn, pass, MO_64);
10915 read_vec_element(s, tcg_op2, rm, pass, MO_64);
10916
10917 handle_3same_64(s, opcode, u, tcg_res, tcg_op1, tcg_op2);
10918
10919 write_vec_element(s, tcg_res, rd, pass, MO_64);
10920
10921 tcg_temp_free_i64(tcg_res);
10922 tcg_temp_free_i64(tcg_op1);
10923 tcg_temp_free_i64(tcg_op2);
10924 }
10925 } else {
10926 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
10927 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
10928 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10929 TCGv_i32 tcg_res = tcg_temp_new_i32();
6d9571f7
PM
10930 NeonGenTwoOpFn *genfn = NULL;
10931 NeonGenTwoOpEnvFn *genenvfn = NULL;
1f8a73af
PM
10932
10933 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
10934 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
10935
10936 switch (opcode) {
8b12a0cf
PM
10937 case 0x0: /* SHADD, UHADD */
10938 {
10939 static NeonGenTwoOpFn * const fns[3][2] = {
10940 { gen_helper_neon_hadd_s8, gen_helper_neon_hadd_u8 },
10941 { gen_helper_neon_hadd_s16, gen_helper_neon_hadd_u16 },
10942 { gen_helper_neon_hadd_s32, gen_helper_neon_hadd_u32 },
10943 };
10944 genfn = fns[size][u];
10945 break;
10946 }
6d9571f7
PM
10947 case 0x1: /* SQADD, UQADD */
10948 {
10949 static NeonGenTwoOpEnvFn * const fns[3][2] = {
10950 { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
10951 { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
10952 { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
10953 };
10954 genenvfn = fns[size][u];
10955 break;
10956 }
8b12a0cf
PM
10957 case 0x2: /* SRHADD, URHADD */
10958 {
10959 static NeonGenTwoOpFn * const fns[3][2] = {
10960 { gen_helper_neon_rhadd_s8, gen_helper_neon_rhadd_u8 },
10961 { gen_helper_neon_rhadd_s16, gen_helper_neon_rhadd_u16 },
10962 { gen_helper_neon_rhadd_s32, gen_helper_neon_rhadd_u32 },
10963 };
10964 genfn = fns[size][u];
10965 break;
10966 }
10967 case 0x4: /* SHSUB, UHSUB */
10968 {
10969 static NeonGenTwoOpFn * const fns[3][2] = {
10970 { gen_helper_neon_hsub_s8, gen_helper_neon_hsub_u8 },
10971 { gen_helper_neon_hsub_s16, gen_helper_neon_hsub_u16 },
10972 { gen_helper_neon_hsub_s32, gen_helper_neon_hsub_u32 },
10973 };
10974 genfn = fns[size][u];
10975 break;
10976 }
6d9571f7
PM
10977 case 0x5: /* SQSUB, UQSUB */
10978 {
10979 static NeonGenTwoOpEnvFn * const fns[3][2] = {
10980 { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
10981 { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
10982 { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
10983 };
10984 genenvfn = fns[size][u];
10985 break;
10986 }
6d9571f7
PM
10987 case 0x8: /* SSHL, USHL */
10988 {
10989 static NeonGenTwoOpFn * const fns[3][2] = {
10990 { gen_helper_neon_shl_s8, gen_helper_neon_shl_u8 },
10991 { gen_helper_neon_shl_s16, gen_helper_neon_shl_u16 },
10992 { gen_helper_neon_shl_s32, gen_helper_neon_shl_u32 },
10993 };
10994 genfn = fns[size][u];
10995 break;
10996 }
10997 case 0x9: /* SQSHL, UQSHL */
10998 {
10999 static NeonGenTwoOpEnvFn * const fns[3][2] = {
11000 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
11001 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
11002 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
11003 };
11004 genenvfn = fns[size][u];
11005 break;
11006 }
11007 case 0xa: /* SRSHL, URSHL */
11008 {
11009 static NeonGenTwoOpFn * const fns[3][2] = {
11010 { gen_helper_neon_rshl_s8, gen_helper_neon_rshl_u8 },
11011 { gen_helper_neon_rshl_s16, gen_helper_neon_rshl_u16 },
11012 { gen_helper_neon_rshl_s32, gen_helper_neon_rshl_u32 },
11013 };
11014 genfn = fns[size][u];
11015 break;
11016 }
11017 case 0xb: /* SQRSHL, UQRSHL */
11018 {
11019 static NeonGenTwoOpEnvFn * const fns[3][2] = {
11020 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
11021 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
11022 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
11023 };
11024 genenvfn = fns[size][u];
11025 break;
11026 }
8b12a0cf
PM
11027 case 0xc: /* SMAX, UMAX */
11028 {
11029 static NeonGenTwoOpFn * const fns[3][2] = {
11030 { gen_helper_neon_max_s8, gen_helper_neon_max_u8 },
11031 { gen_helper_neon_max_s16, gen_helper_neon_max_u16 },
ecb8ab8d 11032 { tcg_gen_smax_i32, tcg_gen_umax_i32 },
8b12a0cf
PM
11033 };
11034 genfn = fns[size][u];
11035 break;
11036 }
11037
11038 case 0xd: /* SMIN, UMIN */
11039 {
11040 static NeonGenTwoOpFn * const fns[3][2] = {
11041 { gen_helper_neon_min_s8, gen_helper_neon_min_u8 },
11042 { gen_helper_neon_min_s16, gen_helper_neon_min_u16 },
ecb8ab8d 11043 { tcg_gen_smin_i32, tcg_gen_umin_i32 },
8b12a0cf
PM
11044 };
11045 genfn = fns[size][u];
11046 break;
11047 }
11048 case 0xe: /* SABD, UABD */
11049 case 0xf: /* SABA, UABA */
11050 {
11051 static NeonGenTwoOpFn * const fns[3][2] = {
11052 { gen_helper_neon_abd_s8, gen_helper_neon_abd_u8 },
11053 { gen_helper_neon_abd_s16, gen_helper_neon_abd_u16 },
11054 { gen_helper_neon_abd_s32, gen_helper_neon_abd_u32 },
11055 };
11056 genfn = fns[size][u];
11057 break;
11058 }
8b12a0cf 11059 case 0x13: /* MUL, PMUL */
0c7c55c4
RH
11060 assert(u); /* PMUL */
11061 assert(size == 0);
11062 genfn = gen_helper_neon_mul_p8;
8b12a0cf 11063 break;
8b12a0cf
PM
11064 case 0x16: /* SQDMULH, SQRDMULH */
11065 {
11066 static NeonGenTwoOpEnvFn * const fns[2][2] = {
11067 { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
11068 { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
11069 };
11070 assert(size == 1 || size == 2);
11071 genenvfn = fns[size - 1][u];
11072 break;
11073 }
1f8a73af
PM
11074 default:
11075 g_assert_not_reached();
11076 }
11077
6d9571f7
PM
11078 if (genenvfn) {
11079 genenvfn(tcg_res, cpu_env, tcg_op1, tcg_op2);
11080 } else {
11081 genfn(tcg_res, tcg_op1, tcg_op2);
11082 }
1f8a73af 11083
0c7c55c4
RH
11084 if (opcode == 0xf) {
11085 /* SABA, UABA: accumulating ops */
11086 static NeonGenTwoOpFn * const fns[3] = {
11087 gen_helper_neon_add_u8,
11088 gen_helper_neon_add_u16,
11089 tcg_gen_add_i32,
8b12a0cf 11090 };
8b12a0cf 11091
8b12a0cf 11092 read_vec_element_i32(s, tcg_op1, rd, pass, MO_32);
0c7c55c4 11093 fns[size](tcg_res, tcg_op1, tcg_res);
8b12a0cf
PM
11094 }
11095
1f8a73af
PM
11096 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
11097
11098 tcg_temp_free_i32(tcg_res);
11099 tcg_temp_free_i32(tcg_op1);
11100 tcg_temp_free_i32(tcg_op2);
11101 }
11102 }
4ff55bcb 11103 clear_vec_high(s, is_q, rd);
e1cea114
PM
11104}
11105
4ce31af4 11106/* AdvSIMD three same
384b26fb
AB
11107 * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
11108 * +---+---+---+-----------+------+---+------+--------+---+------+------+
11109 * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
11110 * +---+---+---+-----------+------+---+------+--------+---+------+------+
11111 */
11112static void disas_simd_three_reg_same(DisasContext *s, uint32_t insn)
11113{
e1cea114
PM
11114 int opcode = extract32(insn, 11, 5);
11115
11116 switch (opcode) {
11117 case 0x3: /* logic ops */
11118 disas_simd_3same_logic(s, insn);
11119 break;
11120 case 0x17: /* ADDP */
11121 case 0x14: /* SMAXP, UMAXP */
11122 case 0x15: /* SMINP, UMINP */
bc242f9b 11123 {
e1cea114 11124 /* Pairwise operations */
bc242f9b
AB
11125 int is_q = extract32(insn, 30, 1);
11126 int u = extract32(insn, 29, 1);
11127 int size = extract32(insn, 22, 2);
11128 int rm = extract32(insn, 16, 5);
11129 int rn = extract32(insn, 5, 5);
11130 int rd = extract32(insn, 0, 5);
11131 if (opcode == 0x17) {
11132 if (u || (size == 3 && !is_q)) {
11133 unallocated_encoding(s);
11134 return;
11135 }
11136 } else {
11137 if (size == 3) {
11138 unallocated_encoding(s);
11139 return;
11140 }
11141 }
11142 handle_simd_3same_pair(s, is_q, u, opcode, size, rn, rm, rd);
e1cea114 11143 break;
bc242f9b 11144 }
e1cea114
PM
11145 case 0x18 ... 0x31:
11146 /* floating point ops, sz[1] and U are part of opcode */
11147 disas_simd_3same_float(s, insn);
11148 break;
11149 default:
11150 disas_simd_3same_int(s, insn);
11151 break;
11152 }
384b26fb
AB
11153}
11154
376e8d6c
AB
11155/*
11156 * Advanced SIMD three same (ARMv8.2 FP16 variants)
11157 *
11158 * 31 30 29 28 24 23 22 21 20 16 15 14 13 11 10 9 5 4 0
11159 * +---+---+---+-----------+---------+------+-----+--------+---+------+------+
11160 * | 0 | Q | U | 0 1 1 1 0 | a | 1 0 | Rm | 0 0 | opcode | 1 | Rn | Rd |
11161 * +---+---+---+-----------+---------+------+-----+--------+---+------+------+
11162 *
11163 * This includes FMULX, FCMEQ (register), FRECPS, FRSQRTS, FCMGE
11164 * (register), FACGE, FABD, FCMGT (register) and FACGT.
11165 *
11166 */
11167static void disas_simd_three_reg_same_fp16(DisasContext *s, uint32_t insn)
11168{
11169 int opcode, fpopcode;
11170 int is_q, u, a, rm, rn, rd;
11171 int datasize, elements;
11172 int pass;
11173 TCGv_ptr fpst;
7a2c6e61 11174 bool pairwise = false;
376e8d6c 11175
5763190f 11176 if (!dc_isar_feature(aa64_fp16, s)) {
376e8d6c
AB
11177 unallocated_encoding(s);
11178 return;
11179 }
11180
11181 if (!fp_access_check(s)) {
11182 return;
11183 }
11184
11185 /* For these floating point ops, the U, a and opcode bits
11186 * together indicate the operation.
11187 */
11188 opcode = extract32(insn, 11, 3);
11189 u = extract32(insn, 29, 1);
11190 a = extract32(insn, 23, 1);
11191 is_q = extract32(insn, 30, 1);
11192 rm = extract32(insn, 16, 5);
11193 rn = extract32(insn, 5, 5);
11194 rd = extract32(insn, 0, 5);
11195
11196 fpopcode = opcode | (a << 3) | (u << 4);
11197 datasize = is_q ? 128 : 64;
11198 elements = datasize / 16;
11199
7a2c6e61
AB
11200 switch (fpopcode) {
11201 case 0x10: /* FMAXNMP */
11202 case 0x12: /* FADDP */
11203 case 0x16: /* FMAXP */
11204 case 0x18: /* FMINNMP */
11205 case 0x1e: /* FMINP */
11206 pairwise = true;
11207 break;
11208 }
11209
376e8d6c
AB
11210 fpst = get_fpstatus_ptr(true);
11211
7a2c6e61
AB
11212 if (pairwise) {
11213 int maxpass = is_q ? 8 : 4;
376e8d6c
AB
11214 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
11215 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7a2c6e61 11216 TCGv_i32 tcg_res[8];
376e8d6c 11217
7a2c6e61
AB
11218 for (pass = 0; pass < maxpass; pass++) {
11219 int passreg = pass < (maxpass / 2) ? rn : rm;
11220 int passelt = (pass << 1) & (maxpass - 1);
376e8d6c 11221
7a2c6e61
AB
11222 read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_16);
11223 read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_16);
11224 tcg_res[pass] = tcg_temp_new_i32();
11225
11226 switch (fpopcode) {
11227 case 0x10: /* FMAXNMP */
11228 gen_helper_advsimd_maxnumh(tcg_res[pass], tcg_op1, tcg_op2,
11229 fpst);
11230 break;
11231 case 0x12: /* FADDP */
11232 gen_helper_advsimd_addh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11233 break;
11234 case 0x16: /* FMAXP */
11235 gen_helper_advsimd_maxh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11236 break;
11237 case 0x18: /* FMINNMP */
11238 gen_helper_advsimd_minnumh(tcg_res[pass], tcg_op1, tcg_op2,
11239 fpst);
11240 break;
11241 case 0x1e: /* FMINP */
11242 gen_helper_advsimd_minh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11243 break;
11244 default:
11245 g_assert_not_reached();
11246 }
11247 }
11248
11249 for (pass = 0; pass < maxpass; pass++) {
11250 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_16);
11251 tcg_temp_free_i32(tcg_res[pass]);
376e8d6c
AB
11252 }
11253
376e8d6c
AB
11254 tcg_temp_free_i32(tcg_op1);
11255 tcg_temp_free_i32(tcg_op2);
7a2c6e61
AB
11256
11257 } else {
11258 for (pass = 0; pass < elements; pass++) {
11259 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
11260 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
11261 TCGv_i32 tcg_res = tcg_temp_new_i32();
11262
11263 read_vec_element_i32(s, tcg_op1, rn, pass, MO_16);
11264 read_vec_element_i32(s, tcg_op2, rm, pass, MO_16);
11265
11266 switch (fpopcode) {
11267 case 0x0: /* FMAXNM */
11268 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
11269 break;
11270 case 0x1: /* FMLA */
11271 read_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11272 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_res,
11273 fpst);
11274 break;
11275 case 0x2: /* FADD */
11276 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
11277 break;
11278 case 0x3: /* FMULX */
11279 gen_helper_advsimd_mulxh(tcg_res, tcg_op1, tcg_op2, fpst);
11280 break;
11281 case 0x4: /* FCMEQ */
11282 gen_helper_advsimd_ceq_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11283 break;
11284 case 0x6: /* FMAX */
11285 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
11286 break;
11287 case 0x7: /* FRECPS */
11288 gen_helper_recpsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11289 break;
11290 case 0x8: /* FMINNM */
11291 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
11292 break;
11293 case 0x9: /* FMLS */
11294 /* As usual for ARM, separate negation for fused multiply-add */
11295 tcg_gen_xori_i32(tcg_op1, tcg_op1, 0x8000);
11296 read_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11297 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_res,
11298 fpst);
11299 break;
11300 case 0xa: /* FSUB */
11301 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
11302 break;
11303 case 0xe: /* FMIN */
11304 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
11305 break;
11306 case 0xf: /* FRSQRTS */
11307 gen_helper_rsqrtsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11308 break;
11309 case 0x13: /* FMUL */
11310 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
11311 break;
11312 case 0x14: /* FCMGE */
11313 gen_helper_advsimd_cge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11314 break;
11315 case 0x15: /* FACGE */
11316 gen_helper_advsimd_acge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11317 break;
11318 case 0x17: /* FDIV */
11319 gen_helper_advsimd_divh(tcg_res, tcg_op1, tcg_op2, fpst);
11320 break;
11321 case 0x1a: /* FABD */
11322 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
11323 tcg_gen_andi_i32(tcg_res, tcg_res, 0x7fff);
11324 break;
11325 case 0x1c: /* FCMGT */
11326 gen_helper_advsimd_cgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11327 break;
11328 case 0x1d: /* FACGT */
11329 gen_helper_advsimd_acgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11330 break;
11331 default:
11332 fprintf(stderr, "%s: insn %#04x, fpop %#2x @ %#" PRIx64 "\n",
11333 __func__, insn, fpopcode, s->pc);
11334 g_assert_not_reached();
11335 }
11336
11337 write_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11338 tcg_temp_free_i32(tcg_res);
11339 tcg_temp_free_i32(tcg_op1);
11340 tcg_temp_free_i32(tcg_op2);
11341 }
376e8d6c
AB
11342 }
11343
11344 tcg_temp_free_ptr(fpst);
11345
11346 clear_vec_high(s, is_q, rd);
11347}
11348
e7186d82
RH
11349/* AdvSIMD three same extra
11350 * 31 30 29 28 24 23 22 21 20 16 15 14 11 10 9 5 4 0
11351 * +---+---+---+-----------+------+---+------+---+--------+---+----+----+
11352 * | 0 | Q | U | 0 1 1 1 0 | size | 0 | Rm | 1 | opcode | 1 | Rn | Rd |
11353 * +---+---+---+-----------+------+---+------+---+--------+---+----+----+
11354 */
11355static void disas_simd_three_reg_same_extra(DisasContext *s, uint32_t insn)
11356{
11357 int rd = extract32(insn, 0, 5);
11358 int rn = extract32(insn, 5, 5);
11359 int opcode = extract32(insn, 11, 4);
11360 int rm = extract32(insn, 16, 5);
11361 int size = extract32(insn, 22, 2);
11362 bool u = extract32(insn, 29, 1);
11363 bool is_q = extract32(insn, 30, 1);
962fcbf2
RH
11364 bool feature;
11365 int rot;
e7186d82
RH
11366
11367 switch (u * 16 + opcode) {
11368 case 0x10: /* SQRDMLAH (vector) */
11369 case 0x11: /* SQRDMLSH (vector) */
11370 if (size != 1 && size != 2) {
11371 unallocated_encoding(s);
11372 return;
11373 }
962fcbf2 11374 feature = dc_isar_feature(aa64_rdm, s);
e7186d82 11375 break;
26c470a7
RH
11376 case 0x02: /* SDOT (vector) */
11377 case 0x12: /* UDOT (vector) */
11378 if (size != MO_32) {
11379 unallocated_encoding(s);
11380 return;
11381 }
962fcbf2 11382 feature = dc_isar_feature(aa64_dp, s);
26c470a7 11383 break;
b8a4a96d
RH
11384 case 0x18: /* FCMLA, #0 */
11385 case 0x19: /* FCMLA, #90 */
11386 case 0x1a: /* FCMLA, #180 */
11387 case 0x1b: /* FCMLA, #270 */
11388 case 0x1c: /* FCADD, #90 */
11389 case 0x1e: /* FCADD, #270 */
1695cd61 11390 if (size == 0
5763190f 11391 || (size == 1 && !dc_isar_feature(aa64_fp16, s))
1695cd61
RH
11392 || (size == 3 && !is_q)) {
11393 unallocated_encoding(s);
11394 return;
11395 }
962fcbf2 11396 feature = dc_isar_feature(aa64_fcma, s);
1695cd61 11397 break;
e7186d82
RH
11398 default:
11399 unallocated_encoding(s);
11400 return;
11401 }
962fcbf2 11402 if (!feature) {
e7186d82
RH
11403 unallocated_encoding(s);
11404 return;
11405 }
11406 if (!fp_access_check(s)) {
11407 return;
11408 }
11409
11410 switch (opcode) {
11411 case 0x0: /* SQRDMLAH (vector) */
11412 switch (size) {
11413 case 1:
11414 gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlah_s16);
11415 break;
11416 case 2:
11417 gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlah_s32);
11418 break;
11419 default:
11420 g_assert_not_reached();
11421 }
11422 return;
11423
11424 case 0x1: /* SQRDMLSH (vector) */
11425 switch (size) {
11426 case 1:
11427 gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlsh_s16);
11428 break;
11429 case 2:
11430 gen_gvec_op3_env(s, is_q, rd, rn, rm, gen_helper_gvec_qrdmlsh_s32);
11431 break;
11432 default:
11433 g_assert_not_reached();
11434 }
11435 return;
11436
26c470a7
RH
11437 case 0x2: /* SDOT / UDOT */
11438 gen_gvec_op3_ool(s, is_q, rd, rn, rm, 0,
11439 u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b);
11440 return;
11441
d17b7cdc
RH
11442 case 0x8: /* FCMLA, #0 */
11443 case 0x9: /* FCMLA, #90 */
11444 case 0xa: /* FCMLA, #180 */
11445 case 0xb: /* FCMLA, #270 */
11446 rot = extract32(opcode, 0, 2);
11447 switch (size) {
11448 case 1:
11449 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, true, rot,
11450 gen_helper_gvec_fcmlah);
11451 break;
11452 case 2:
11453 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, false, rot,
11454 gen_helper_gvec_fcmlas);
11455 break;
11456 case 3:
11457 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, false, rot,
11458 gen_helper_gvec_fcmlad);
11459 break;
11460 default:
11461 g_assert_not_reached();
11462 }
11463 return;
11464
1695cd61
RH
11465 case 0xc: /* FCADD, #90 */
11466 case 0xe: /* FCADD, #270 */
11467 rot = extract32(opcode, 1, 1);
11468 switch (size) {
11469 case 1:
11470 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11471 gen_helper_gvec_fcaddh);
11472 break;
11473 case 2:
11474 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11475 gen_helper_gvec_fcadds);
11476 break;
11477 case 3:
11478 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11479 gen_helper_gvec_fcaddd);
11480 break;
11481 default:
11482 g_assert_not_reached();
11483 }
11484 return;
11485
e7186d82
RH
11486 default:
11487 g_assert_not_reached();
11488 }
11489}
11490
931c8cc2
PM
11491static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q,
11492 int size, int rn, int rd)
11493{
11494 /* Handle 2-reg-misc ops which are widening (so each size element
11495 * in the source becomes a 2*size element in the destination.
11496 * The only instruction like this is FCVTL.
11497 */
11498 int pass;
11499
11500 if (size == 3) {
11501 /* 32 -> 64 bit fp conversion */
11502 TCGv_i64 tcg_res[2];
11503 int srcelt = is_q ? 2 : 0;
11504
11505 for (pass = 0; pass < 2; pass++) {
11506 TCGv_i32 tcg_op = tcg_temp_new_i32();
11507 tcg_res[pass] = tcg_temp_new_i64();
11508
11509 read_vec_element_i32(s, tcg_op, rn, srcelt + pass, MO_32);
11510 gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, cpu_env);
11511 tcg_temp_free_i32(tcg_op);
11512 }
11513 for (pass = 0; pass < 2; pass++) {
11514 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11515 tcg_temp_free_i64(tcg_res[pass]);
11516 }
11517 } else {
11518 /* 16 -> 32 bit fp conversion */
11519 int srcelt = is_q ? 4 : 0;
11520 TCGv_i32 tcg_res[4];
486624fc
AB
11521 TCGv_ptr fpst = get_fpstatus_ptr(false);
11522 TCGv_i32 ahp = get_ahp_flag();
931c8cc2
PM
11523
11524 for (pass = 0; pass < 4; pass++) {
11525 tcg_res[pass] = tcg_temp_new_i32();
11526
11527 read_vec_element_i32(s, tcg_res[pass], rn, srcelt + pass, MO_16);
11528 gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
486624fc 11529 fpst, ahp);
931c8cc2
PM
11530 }
11531 for (pass = 0; pass < 4; pass++) {
11532 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
11533 tcg_temp_free_i32(tcg_res[pass]);
11534 }
486624fc
AB
11535
11536 tcg_temp_free_ptr(fpst);
11537 tcg_temp_free_i32(ahp);
931c8cc2
PM
11538 }
11539}
11540
39d82118
AB
11541static void handle_rev(DisasContext *s, int opcode, bool u,
11542 bool is_q, int size, int rn, int rd)
11543{
11544 int op = (opcode << 1) | u;
11545 int opsz = op + size;
11546 int grp_size = 3 - opsz;
11547 int dsize = is_q ? 128 : 64;
11548 int i;
11549
11550 if (opsz >= 3) {
11551 unallocated_encoding(s);
11552 return;
11553 }
11554
8c6afa6a
PM
11555 if (!fp_access_check(s)) {
11556 return;
11557 }
11558
39d82118
AB
11559 if (size == 0) {
11560 /* Special case bytes, use bswap op on each group of elements */
11561 int groups = dsize / (8 << grp_size);
11562
11563 for (i = 0; i < groups; i++) {
11564 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
11565
11566 read_vec_element(s, tcg_tmp, rn, i, grp_size);
11567 switch (grp_size) {
11568 case MO_16:
11569 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
11570 break;
11571 case MO_32:
11572 tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
11573 break;
11574 case MO_64:
11575 tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp);
11576 break;
11577 default:
11578 g_assert_not_reached();
11579 }
11580 write_vec_element(s, tcg_tmp, rd, i, grp_size);
11581 tcg_temp_free_i64(tcg_tmp);
11582 }
4ff55bcb 11583 clear_vec_high(s, is_q, rd);
39d82118
AB
11584 } else {
11585 int revmask = (1 << grp_size) - 1;
11586 int esize = 8 << size;
11587 int elements = dsize / esize;
11588 TCGv_i64 tcg_rn = tcg_temp_new_i64();
11589 TCGv_i64 tcg_rd = tcg_const_i64(0);
11590 TCGv_i64 tcg_rd_hi = tcg_const_i64(0);
11591
11592 for (i = 0; i < elements; i++) {
11593 int e_rev = (i & 0xf) ^ revmask;
11594 int off = e_rev * esize;
11595 read_vec_element(s, tcg_rn, rn, i, size);
11596 if (off >= 64) {
11597 tcg_gen_deposit_i64(tcg_rd_hi, tcg_rd_hi,
11598 tcg_rn, off - 64, esize);
11599 } else {
11600 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, off, esize);
11601 }
11602 }
11603 write_vec_element(s, tcg_rd, rd, 0, MO_64);
11604 write_vec_element(s, tcg_rd_hi, rd, 1, MO_64);
11605
11606 tcg_temp_free_i64(tcg_rd_hi);
11607 tcg_temp_free_i64(tcg_rd);
11608 tcg_temp_free_i64(tcg_rn);
11609 }
11610}
11611
6781fa11
PM
11612static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u,
11613 bool is_q, int size, int rn, int rd)
11614{
11615 /* Implement the pairwise operations from 2-misc:
11616 * SADDLP, UADDLP, SADALP, UADALP.
11617 * These all add pairs of elements in the input to produce a
11618 * double-width result element in the output (possibly accumulating).
11619 */
11620 bool accum = (opcode == 0x6);
11621 int maxpass = is_q ? 2 : 1;
11622 int pass;
11623 TCGv_i64 tcg_res[2];
11624
11625 if (size == 2) {
11626 /* 32 + 32 -> 64 op */
11627 TCGMemOp memop = size + (u ? 0 : MO_SIGN);
11628
11629 for (pass = 0; pass < maxpass; pass++) {
11630 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
11631 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
11632
11633 tcg_res[pass] = tcg_temp_new_i64();
11634
11635 read_vec_element(s, tcg_op1, rn, pass * 2, memop);
11636 read_vec_element(s, tcg_op2, rn, pass * 2 + 1, memop);
11637 tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
11638 if (accum) {
11639 read_vec_element(s, tcg_op1, rd, pass, MO_64);
11640 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
11641 }
11642
11643 tcg_temp_free_i64(tcg_op1);
11644 tcg_temp_free_i64(tcg_op2);
11645 }
11646 } else {
11647 for (pass = 0; pass < maxpass; pass++) {
11648 TCGv_i64 tcg_op = tcg_temp_new_i64();
11649 NeonGenOneOpFn *genfn;
11650 static NeonGenOneOpFn * const fns[2][2] = {
11651 { gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 },
11652 { gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 },
11653 };
11654
11655 genfn = fns[size][u];
11656
11657 tcg_res[pass] = tcg_temp_new_i64();
11658
11659 read_vec_element(s, tcg_op, rn, pass, MO_64);
11660 genfn(tcg_res[pass], tcg_op);
11661
11662 if (accum) {
11663 read_vec_element(s, tcg_op, rd, pass, MO_64);
11664 if (size == 0) {
11665 gen_helper_neon_addl_u16(tcg_res[pass],
11666 tcg_res[pass], tcg_op);
11667 } else {
11668 gen_helper_neon_addl_u32(tcg_res[pass],
11669 tcg_res[pass], tcg_op);
11670 }
11671 }
11672 tcg_temp_free_i64(tcg_op);
11673 }
11674 }
11675 if (!is_q) {
11676 tcg_res[1] = tcg_const_i64(0);
11677 }
11678 for (pass = 0; pass < 2; pass++) {
11679 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11680 tcg_temp_free_i64(tcg_res[pass]);
11681 }
11682}
11683
73a81d10
PM
11684static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd)
11685{
11686 /* Implement SHLL and SHLL2 */
11687 int pass;
11688 int part = is_q ? 2 : 0;
11689 TCGv_i64 tcg_res[2];
11690
11691 for (pass = 0; pass < 2; pass++) {
11692 static NeonGenWidenFn * const widenfns[3] = {
11693 gen_helper_neon_widen_u8,
11694 gen_helper_neon_widen_u16,
11695 tcg_gen_extu_i32_i64,
11696 };
11697 NeonGenWidenFn *widenfn = widenfns[size];
11698 TCGv_i32 tcg_op = tcg_temp_new_i32();
11699
11700 read_vec_element_i32(s, tcg_op, rn, part + pass, MO_32);
11701 tcg_res[pass] = tcg_temp_new_i64();
11702 widenfn(tcg_res[pass], tcg_op);
11703 tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << size);
11704
11705 tcg_temp_free_i32(tcg_op);
11706 }
11707
11708 for (pass = 0; pass < 2; pass++) {
11709 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11710 tcg_temp_free_i64(tcg_res[pass]);
11711 }
11712}
11713
4ce31af4 11714/* AdvSIMD two reg misc
384b26fb
AB
11715 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
11716 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
11717 * | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
11718 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
11719 */
11720static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
11721{
45aecc6d
PM
11722 int size = extract32(insn, 22, 2);
11723 int opcode = extract32(insn, 12, 5);
11724 bool u = extract32(insn, 29, 1);
11725 bool is_q = extract32(insn, 30, 1);
94b6c911
PM
11726 int rn = extract32(insn, 5, 5);
11727 int rd = extract32(insn, 0, 5);
04c7c6c2
PM
11728 bool need_fpstatus = false;
11729 bool need_rmode = false;
11730 int rmode = -1;
11731 TCGv_i32 tcg_rmode;
11732 TCGv_ptr tcg_fpstatus;
45aecc6d
PM
11733
11734 switch (opcode) {
11735 case 0x0: /* REV64, REV32 */
11736 case 0x1: /* REV16 */
39d82118 11737 handle_rev(s, opcode, u, is_q, size, rn, rd);
45aecc6d 11738 return;
86cbc418
PM
11739 case 0x5: /* CNT, NOT, RBIT */
11740 if (u && size == 0) {
377ef731 11741 /* NOT */
86cbc418
PM
11742 break;
11743 } else if (u && size == 1) {
11744 /* RBIT */
11745 break;
11746 } else if (!u && size == 0) {
11747 /* CNT */
11748 break;
45aecc6d 11749 }
86cbc418 11750 unallocated_encoding(s);
45aecc6d 11751 return;
d980fd59
PM
11752 case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */
11753 case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */
11754 if (size == 3) {
11755 unallocated_encoding(s);
11756 return;
11757 }
8c6afa6a
PM
11758 if (!fp_access_check(s)) {
11759 return;
11760 }
11761
5201c136 11762 handle_2misc_narrow(s, false, opcode, u, is_q, size, rn, rd);
d980fd59 11763 return;
45aecc6d 11764 case 0x4: /* CLS, CLZ */
b05c3068
AB
11765 if (size == 3) {
11766 unallocated_encoding(s);
11767 return;
11768 }
11769 break;
11770 case 0x2: /* SADDLP, UADDLP */
45aecc6d 11771 case 0x6: /* SADALP, UADALP */
45aecc6d
PM
11772 if (size == 3) {
11773 unallocated_encoding(s);
11774 return;
11775 }
8c6afa6a
PM
11776 if (!fp_access_check(s)) {
11777 return;
11778 }
6781fa11 11779 handle_2misc_pairwise(s, opcode, u, is_q, size, rn, rd);
45aecc6d
PM
11780 return;
11781 case 0x13: /* SHLL, SHLL2 */
11782 if (u == 0 || size == 3) {
11783 unallocated_encoding(s);
11784 return;
11785 }
8c6afa6a
PM
11786 if (!fp_access_check(s)) {
11787 return;
11788 }
73a81d10 11789 handle_shll(s, is_q, size, rn, rd);
45aecc6d
PM
11790 return;
11791 case 0xa: /* CMLT */
11792 if (u == 1) {
11793 unallocated_encoding(s);
11794 return;
11795 }
11796 /* fall through */
45aecc6d
PM
11797 case 0x8: /* CMGT, CMGE */
11798 case 0x9: /* CMEQ, CMLE */
11799 case 0xb: /* ABS, NEG */
94b6c911
PM
11800 if (size == 3 && !is_q) {
11801 unallocated_encoding(s);
11802 return;
11803 }
11804 break;
11805 case 0x3: /* SUQADD, USQADD */
09e03735
AB
11806 if (size == 3 && !is_q) {
11807 unallocated_encoding(s);
11808 return;
11809 }
8c6afa6a
PM
11810 if (!fp_access_check(s)) {
11811 return;
11812 }
09e03735
AB
11813 handle_2misc_satacc(s, false, u, is_q, size, rn, rd);
11814 return;
94b6c911 11815 case 0x7: /* SQABS, SQNEG */
45aecc6d
PM
11816 if (size == 3 && !is_q) {
11817 unallocated_encoding(s);
11818 return;
11819 }
0a79bc87 11820 break;
45aecc6d
PM
11821 case 0xc ... 0xf:
11822 case 0x16 ... 0x1d:
11823 case 0x1f:
11824 {
11825 /* Floating point: U, size[1] and opcode indicate operation;
11826 * size[0] indicates single or double precision.
11827 */
10113b69 11828 int is_double = extract32(size, 0, 1);
45aecc6d 11829 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
10113b69 11830 size = is_double ? 3 : 2;
45aecc6d 11831 switch (opcode) {
f93d0138
PM
11832 case 0x2f: /* FABS */
11833 case 0x6f: /* FNEG */
11834 if (size == 3 && !is_q) {
11835 unallocated_encoding(s);
11836 return;
11837 }
11838 break;
10113b69
AB
11839 case 0x1d: /* SCVTF */
11840 case 0x5d: /* UCVTF */
11841 {
11842 bool is_signed = (opcode == 0x1d) ? true : false;
11843 int elements = is_double ? 2 : is_q ? 4 : 2;
11844 if (is_double && !is_q) {
11845 unallocated_encoding(s);
11846 return;
11847 }
8c6afa6a
PM
11848 if (!fp_access_check(s)) {
11849 return;
11850 }
10113b69
AB
11851 handle_simd_intfp_conv(s, rd, rn, elements, is_signed, 0, size);
11852 return;
11853 }
8908f4d1
AB
11854 case 0x2c: /* FCMGT (zero) */
11855 case 0x2d: /* FCMEQ (zero) */
11856 case 0x2e: /* FCMLT (zero) */
11857 case 0x6c: /* FCMGE (zero) */
11858 case 0x6d: /* FCMLE (zero) */
11859 if (size == 3 && !is_q) {
11860 unallocated_encoding(s);
11861 return;
11862 }
11863 handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd);
11864 return;
f612537e
AB
11865 case 0x7f: /* FSQRT */
11866 if (size == 3 && !is_q) {
11867 unallocated_encoding(s);
11868 return;
11869 }
11870 break;
04c7c6c2
PM
11871 case 0x1a: /* FCVTNS */
11872 case 0x1b: /* FCVTMS */
11873 case 0x3a: /* FCVTPS */
11874 case 0x3b: /* FCVTZS */
11875 case 0x5a: /* FCVTNU */
11876 case 0x5b: /* FCVTMU */
11877 case 0x7a: /* FCVTPU */
11878 case 0x7b: /* FCVTZU */
11879 need_fpstatus = true;
11880 need_rmode = true;
11881 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
11882 if (size == 3 && !is_q) {
11883 unallocated_encoding(s);
11884 return;
11885 }
11886 break;
11887 case 0x5c: /* FCVTAU */
11888 case 0x1c: /* FCVTAS */
11889 need_fpstatus = true;
11890 need_rmode = true;
11891 rmode = FPROUNDING_TIEAWAY;
11892 if (size == 3 && !is_q) {
11893 unallocated_encoding(s);
11894 return;
11895 }
11896 break;
b6d4443a
AB
11897 case 0x3c: /* URECPE */
11898 if (size == 3) {
11899 unallocated_encoding(s);
11900 return;
11901 }
11902 /* fall through */
11903 case 0x3d: /* FRECPE */
c2fb418e
AB
11904 case 0x7d: /* FRSQRTE */
11905 if (size == 3 && !is_q) {
11906 unallocated_encoding(s);
11907 return;
11908 }
8c6afa6a
PM
11909 if (!fp_access_check(s)) {
11910 return;
11911 }
b6d4443a
AB
11912 handle_2misc_reciprocal(s, opcode, false, u, is_q, size, rn, rd);
11913 return;
5553955e
PM
11914 case 0x56: /* FCVTXN, FCVTXN2 */
11915 if (size == 2) {
11916 unallocated_encoding(s);
11917 return;
11918 }
11919 /* fall through */
45aecc6d 11920 case 0x16: /* FCVTN, FCVTN2 */
261a5b4d
PM
11921 /* handle_2misc_narrow does a 2*size -> size operation, but these
11922 * instructions encode the source size rather than dest size.
11923 */
8c6afa6a
PM
11924 if (!fp_access_check(s)) {
11925 return;
11926 }
5201c136 11927 handle_2misc_narrow(s, false, opcode, 0, is_q, size - 1, rn, rd);
261a5b4d 11928 return;
45aecc6d 11929 case 0x17: /* FCVTL, FCVTL2 */
8c6afa6a
PM
11930 if (!fp_access_check(s)) {
11931 return;
11932 }
931c8cc2
PM
11933 handle_2misc_widening(s, opcode, is_q, size, rn, rd);
11934 return;
45aecc6d
PM
11935 case 0x18: /* FRINTN */
11936 case 0x19: /* FRINTM */
45aecc6d
PM
11937 case 0x38: /* FRINTP */
11938 case 0x39: /* FRINTZ */
03df01ed
PM
11939 need_rmode = true;
11940 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
11941 /* fall through */
11942 case 0x59: /* FRINTX */
11943 case 0x79: /* FRINTI */
11944 need_fpstatus = true;
11945 if (size == 3 && !is_q) {
11946 unallocated_encoding(s);
11947 return;
11948 }
11949 break;
11950 case 0x58: /* FRINTA */
11951 need_rmode = true;
11952 rmode = FPROUNDING_TIEAWAY;
11953 need_fpstatus = true;
11954 if (size == 3 && !is_q) {
11955 unallocated_encoding(s);
11956 return;
11957 }
11958 break;
45aecc6d 11959 case 0x7c: /* URSQRTE */
c2fb418e
AB
11960 if (size == 3) {
11961 unallocated_encoding(s);
11962 return;
11963 }
11964 need_fpstatus = true;
11965 break;
45aecc6d
PM
11966 default:
11967 unallocated_encoding(s);
11968 return;
11969 }
11970 break;
11971 }
11972 default:
11973 unallocated_encoding(s);
11974 return;
11975 }
94b6c911 11976
8c6afa6a
PM
11977 if (!fp_access_check(s)) {
11978 return;
11979 }
11980
9b049916 11981 if (need_fpstatus || need_rmode) {
d81ce0ef 11982 tcg_fpstatus = get_fpstatus_ptr(false);
04c7c6c2 11983 } else {
f764718d 11984 tcg_fpstatus = NULL;
04c7c6c2
PM
11985 }
11986 if (need_rmode) {
11987 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
9b049916 11988 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
04c7c6c2 11989 } else {
f764718d 11990 tcg_rmode = NULL;
04c7c6c2
PM
11991 }
11992
377ef731
RH
11993 switch (opcode) {
11994 case 0x5:
11995 if (u && size == 0) { /* NOT */
11996 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0);
11997 return;
11998 }
11999 break;
12000 case 0xb:
12001 if (u) { /* NEG */
12002 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size);
12003 return;
12004 }
12005 break;
12006 }
12007
94b6c911
PM
12008 if (size == 3) {
12009 /* All 64-bit element operations can be shared with scalar 2misc */
12010 int pass;
12011
a8766e31
RH
12012 /* Coverity claims (size == 3 && !is_q) has been eliminated
12013 * from all paths leading to here.
12014 */
12015 tcg_debug_assert(is_q);
12016 for (pass = 0; pass < 2; pass++) {
94b6c911
PM
12017 TCGv_i64 tcg_op = tcg_temp_new_i64();
12018 TCGv_i64 tcg_res = tcg_temp_new_i64();
12019
12020 read_vec_element(s, tcg_op, rn, pass, MO_64);
12021
04c7c6c2
PM
12022 handle_2misc_64(s, opcode, u, tcg_res, tcg_op,
12023 tcg_rmode, tcg_fpstatus);
94b6c911
PM
12024
12025 write_vec_element(s, tcg_res, rd, pass, MO_64);
12026
12027 tcg_temp_free_i64(tcg_res);
12028 tcg_temp_free_i64(tcg_op);
12029 }
12030 } else {
12031 int pass;
12032
12033 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
12034 TCGv_i32 tcg_op = tcg_temp_new_i32();
12035 TCGv_i32 tcg_res = tcg_temp_new_i32();
12036 TCGCond cond;
12037
12038 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
12039
12040 if (size == 2) {
12041 /* Special cases for 32 bit elements */
12042 switch (opcode) {
12043 case 0xa: /* CMLT */
12044 /* 32 bit integer comparison against zero, result is
12045 * test ? (2^32 - 1) : 0. We implement via setcond(test)
12046 * and inverting.
12047 */
12048 cond = TCG_COND_LT;
12049 do_cmop:
12050 tcg_gen_setcondi_i32(cond, tcg_res, tcg_op, 0);
12051 tcg_gen_neg_i32(tcg_res, tcg_res);
12052 break;
12053 case 0x8: /* CMGT, CMGE */
12054 cond = u ? TCG_COND_GE : TCG_COND_GT;
12055 goto do_cmop;
12056 case 0x9: /* CMEQ, CMLE */
12057 cond = u ? TCG_COND_LE : TCG_COND_EQ;
12058 goto do_cmop;
b05c3068
AB
12059 case 0x4: /* CLS */
12060 if (u) {
7539a012 12061 tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
b05c3068 12062 } else {
bc21dbcc 12063 tcg_gen_clrsb_i32(tcg_res, tcg_op);
b05c3068
AB
12064 }
12065 break;
0a79bc87
AB
12066 case 0x7: /* SQABS, SQNEG */
12067 if (u) {
12068 gen_helper_neon_qneg_s32(tcg_res, cpu_env, tcg_op);
12069 } else {
12070 gen_helper_neon_qabs_s32(tcg_res, cpu_env, tcg_op);
12071 }
12072 break;
94b6c911
PM
12073 case 0xb: /* ABS, NEG */
12074 if (u) {
12075 tcg_gen_neg_i32(tcg_res, tcg_op);
12076 } else {
12077 TCGv_i32 tcg_zero = tcg_const_i32(0);
12078 tcg_gen_neg_i32(tcg_res, tcg_op);
12079 tcg_gen_movcond_i32(TCG_COND_GT, tcg_res, tcg_op,
12080 tcg_zero, tcg_op, tcg_res);
12081 tcg_temp_free_i32(tcg_zero);
12082 }
12083 break;
f93d0138
PM
12084 case 0x2f: /* FABS */
12085 gen_helper_vfp_abss(tcg_res, tcg_op);
12086 break;
12087 case 0x6f: /* FNEG */
12088 gen_helper_vfp_negs(tcg_res, tcg_op);
12089 break;
f612537e
AB
12090 case 0x7f: /* FSQRT */
12091 gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
12092 break;
04c7c6c2
PM
12093 case 0x1a: /* FCVTNS */
12094 case 0x1b: /* FCVTMS */
12095 case 0x1c: /* FCVTAS */
12096 case 0x3a: /* FCVTPS */
12097 case 0x3b: /* FCVTZS */
12098 {
12099 TCGv_i32 tcg_shift = tcg_const_i32(0);
12100 gen_helper_vfp_tosls(tcg_res, tcg_op,
12101 tcg_shift, tcg_fpstatus);
12102 tcg_temp_free_i32(tcg_shift);
12103 break;
12104 }
12105 case 0x5a: /* FCVTNU */
12106 case 0x5b: /* FCVTMU */
12107 case 0x5c: /* FCVTAU */
12108 case 0x7a: /* FCVTPU */
12109 case 0x7b: /* FCVTZU */
12110 {
12111 TCGv_i32 tcg_shift = tcg_const_i32(0);
12112 gen_helper_vfp_touls(tcg_res, tcg_op,
12113 tcg_shift, tcg_fpstatus);
12114 tcg_temp_free_i32(tcg_shift);
12115 break;
12116 }
03df01ed
PM
12117 case 0x18: /* FRINTN */
12118 case 0x19: /* FRINTM */
12119 case 0x38: /* FRINTP */
12120 case 0x39: /* FRINTZ */
12121 case 0x58: /* FRINTA */
12122 case 0x79: /* FRINTI */
12123 gen_helper_rints(tcg_res, tcg_op, tcg_fpstatus);
12124 break;
12125 case 0x59: /* FRINTX */
12126 gen_helper_rints_exact(tcg_res, tcg_op, tcg_fpstatus);
12127 break;
c2fb418e
AB
12128 case 0x7c: /* URSQRTE */
12129 gen_helper_rsqrte_u32(tcg_res, tcg_op, tcg_fpstatus);
12130 break;
94b6c911
PM
12131 default:
12132 g_assert_not_reached();
12133 }
12134 } else {
12135 /* Use helpers for 8 and 16 bit elements */
12136 switch (opcode) {
86cbc418
PM
12137 case 0x5: /* CNT, RBIT */
12138 /* For these two insns size is part of the opcode specifier
12139 * (handled earlier); they always operate on byte elements.
12140 */
12141 if (u) {
12142 gen_helper_neon_rbit_u8(tcg_res, tcg_op);
12143 } else {
12144 gen_helper_neon_cnt_u8(tcg_res, tcg_op);
12145 }
12146 break;
0a79bc87
AB
12147 case 0x7: /* SQABS, SQNEG */
12148 {
12149 NeonGenOneOpEnvFn *genfn;
12150 static NeonGenOneOpEnvFn * const fns[2][2] = {
12151 { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
12152 { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
12153 };
12154 genfn = fns[size][u];
12155 genfn(tcg_res, cpu_env, tcg_op);
12156 break;
12157 }
94b6c911
PM
12158 case 0x8: /* CMGT, CMGE */
12159 case 0x9: /* CMEQ, CMLE */
12160 case 0xa: /* CMLT */
12161 {
12162 static NeonGenTwoOpFn * const fns[3][2] = {
12163 { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_s16 },
12164 { gen_helper_neon_cge_s8, gen_helper_neon_cge_s16 },
12165 { gen_helper_neon_ceq_u8, gen_helper_neon_ceq_u16 },
12166 };
12167 NeonGenTwoOpFn *genfn;
12168 int comp;
12169 bool reverse;
12170 TCGv_i32 tcg_zero = tcg_const_i32(0);
12171
12172 /* comp = index into [CMGT, CMGE, CMEQ, CMLE, CMLT] */
12173 comp = (opcode - 0x8) * 2 + u;
12174 /* ...but LE, LT are implemented as reverse GE, GT */
12175 reverse = (comp > 2);
12176 if (reverse) {
12177 comp = 4 - comp;
12178 }
12179 genfn = fns[comp][size];
12180 if (reverse) {
12181 genfn(tcg_res, tcg_zero, tcg_op);
12182 } else {
12183 genfn(tcg_res, tcg_op, tcg_zero);
12184 }
12185 tcg_temp_free_i32(tcg_zero);
12186 break;
12187 }
12188 case 0xb: /* ABS, NEG */
12189 if (u) {
12190 TCGv_i32 tcg_zero = tcg_const_i32(0);
12191 if (size) {
12192 gen_helper_neon_sub_u16(tcg_res, tcg_zero, tcg_op);
12193 } else {
12194 gen_helper_neon_sub_u8(tcg_res, tcg_zero, tcg_op);
12195 }
12196 tcg_temp_free_i32(tcg_zero);
12197 } else {
12198 if (size) {
12199 gen_helper_neon_abs_s16(tcg_res, tcg_op);
12200 } else {
12201 gen_helper_neon_abs_s8(tcg_res, tcg_op);
12202 }
12203 }
12204 break;
b05c3068
AB
12205 case 0x4: /* CLS, CLZ */
12206 if (u) {
12207 if (size == 0) {
12208 gen_helper_neon_clz_u8(tcg_res, tcg_op);
12209 } else {
12210 gen_helper_neon_clz_u16(tcg_res, tcg_op);
12211 }
12212 } else {
12213 if (size == 0) {
12214 gen_helper_neon_cls_s8(tcg_res, tcg_op);
12215 } else {
12216 gen_helper_neon_cls_s16(tcg_res, tcg_op);
12217 }
12218 }
12219 break;
94b6c911
PM
12220 default:
12221 g_assert_not_reached();
12222 }
12223 }
12224
12225 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
12226
12227 tcg_temp_free_i32(tcg_res);
12228 tcg_temp_free_i32(tcg_op);
12229 }
12230 }
4ff55bcb 12231 clear_vec_high(s, is_q, rd);
04c7c6c2
PM
12232
12233 if (need_rmode) {
9b049916 12234 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
04c7c6c2
PM
12235 tcg_temp_free_i32(tcg_rmode);
12236 }
12237 if (need_fpstatus) {
12238 tcg_temp_free_ptr(tcg_fpstatus);
12239 }
384b26fb
AB
12240}
12241
5d432be6
AB
12242/* AdvSIMD [scalar] two register miscellaneous (FP16)
12243 *
12244 * 31 30 29 28 27 24 23 22 21 17 16 12 11 10 9 5 4 0
12245 * +---+---+---+---+---------+---+-------------+--------+-----+------+------+
12246 * | 0 | Q | U | S | 1 1 1 0 | a | 1 1 1 1 0 0 | opcode | 1 0 | Rn | Rd |
12247 * +---+---+---+---+---------+---+-------------+--------+-----+------+------+
12248 * mask: 1000 1111 0111 1110 0000 1100 0000 0000 0x8f7e 0c00
12249 * val: 0000 1110 0111 1000 0000 1000 0000 0000 0x0e78 0800
12250 *
12251 * This actually covers two groups where scalar access is governed by
12252 * bit 28. A bunch of the instructions (float to integral) only exist
12253 * in the vector form and are un-allocated for the scalar decode. Also
12254 * in the scalar decode Q is always 1.
12255 */
12256static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
12257{
6109aea2
AB
12258 int fpop, opcode, a, u;
12259 int rn, rd;
12260 bool is_q;
12261 bool is_scalar;
12262 bool only_in_vector = false;
12263
12264 int pass;
12265 TCGv_i32 tcg_rmode = NULL;
12266 TCGv_ptr tcg_fpstatus = NULL;
12267 bool need_rmode = false;
15f8a233 12268 bool need_fpst = true;
6109aea2 12269 int rmode;
5d432be6 12270
5763190f 12271 if (!dc_isar_feature(aa64_fp16, s)) {
5d432be6
AB
12272 unallocated_encoding(s);
12273 return;
12274 }
12275
6109aea2
AB
12276 rd = extract32(insn, 0, 5);
12277 rn = extract32(insn, 5, 5);
5d432be6 12278
5d432be6 12279 a = extract32(insn, 23, 1);
6109aea2
AB
12280 u = extract32(insn, 29, 1);
12281 is_scalar = extract32(insn, 28, 1);
12282 is_q = extract32(insn, 30, 1);
12283
12284 opcode = extract32(insn, 12, 5);
5d432be6 12285 fpop = deposit32(opcode, 5, 1, a);
6109aea2 12286 fpop = deposit32(fpop, 6, 1, u);
5d432be6 12287
7d4dd1a7
AB
12288 rd = extract32(insn, 0, 5);
12289 rn = extract32(insn, 5, 5);
12290
5d432be6 12291 switch (fpop) {
93193190
AB
12292 case 0x1d: /* SCVTF */
12293 case 0x5d: /* UCVTF */
12294 {
12295 int elements;
12296
12297 if (is_scalar) {
12298 elements = 1;
12299 } else {
12300 elements = (is_q ? 8 : 4);
12301 }
12302
12303 if (!fp_access_check(s)) {
12304 return;
12305 }
12306 handle_simd_intfp_conv(s, rd, rn, elements, !u, 0, MO_16);
12307 return;
12308 }
7d4dd1a7
AB
12309 break;
12310 case 0x2c: /* FCMGT (zero) */
12311 case 0x2d: /* FCMEQ (zero) */
12312 case 0x2e: /* FCMLT (zero) */
12313 case 0x6c: /* FCMGE (zero) */
12314 case 0x6d: /* FCMLE (zero) */
12315 handle_2misc_fcmp_zero(s, fpop, is_scalar, 0, is_q, MO_16, rn, rd);
12316 return;
fbd06e1e 12317 case 0x3d: /* FRECPE */
98695028 12318 case 0x3f: /* FRECPX */
fbd06e1e 12319 break;
6109aea2
AB
12320 case 0x18: /* FRINTN */
12321 need_rmode = true;
12322 only_in_vector = true;
12323 rmode = FPROUNDING_TIEEVEN;
12324 break;
12325 case 0x19: /* FRINTM */
12326 need_rmode = true;
12327 only_in_vector = true;
12328 rmode = FPROUNDING_NEGINF;
12329 break;
12330 case 0x38: /* FRINTP */
12331 need_rmode = true;
12332 only_in_vector = true;
12333 rmode = FPROUNDING_POSINF;
12334 break;
12335 case 0x39: /* FRINTZ */
12336 need_rmode = true;
12337 only_in_vector = true;
12338 rmode = FPROUNDING_ZERO;
12339 break;
12340 case 0x58: /* FRINTA */
12341 need_rmode = true;
12342 only_in_vector = true;
12343 rmode = FPROUNDING_TIEAWAY;
12344 break;
12345 case 0x59: /* FRINTX */
12346 case 0x79: /* FRINTI */
12347 only_in_vector = true;
12348 /* current rounding mode */
12349 break;
2df58130
AB
12350 case 0x1a: /* FCVTNS */
12351 need_rmode = true;
12352 rmode = FPROUNDING_TIEEVEN;
12353 break;
12354 case 0x1b: /* FCVTMS */
12355 need_rmode = true;
12356 rmode = FPROUNDING_NEGINF;
12357 break;
12358 case 0x1c: /* FCVTAS */
12359 need_rmode = true;
12360 rmode = FPROUNDING_TIEAWAY;
12361 break;
12362 case 0x3a: /* FCVTPS */
12363 need_rmode = true;
12364 rmode = FPROUNDING_POSINF;
12365 break;
12366 case 0x3b: /* FCVTZS */
12367 need_rmode = true;
12368 rmode = FPROUNDING_ZERO;
12369 break;
12370 case 0x5a: /* FCVTNU */
12371 need_rmode = true;
12372 rmode = FPROUNDING_TIEEVEN;
12373 break;
12374 case 0x5b: /* FCVTMU */
12375 need_rmode = true;
12376 rmode = FPROUNDING_NEGINF;
12377 break;
12378 case 0x5c: /* FCVTAU */
12379 need_rmode = true;
12380 rmode = FPROUNDING_TIEAWAY;
12381 break;
12382 case 0x7a: /* FCVTPU */
12383 need_rmode = true;
12384 rmode = FPROUNDING_POSINF;
12385 break;
12386 case 0x7b: /* FCVTZU */
12387 need_rmode = true;
12388 rmode = FPROUNDING_ZERO;
12389 break;
15f8a233
AB
12390 case 0x2f: /* FABS */
12391 case 0x6f: /* FNEG */
12392 need_fpst = false;
12393 break;
c625ff95 12394 case 0x7d: /* FRSQRTE */
b96a54c7
AB
12395 case 0x7f: /* FSQRT (vector) */
12396 break;
5d432be6
AB
12397 default:
12398 fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop);
12399 g_assert_not_reached();
12400 }
12401
6109aea2
AB
12402
12403 /* Check additional constraints for the scalar encoding */
12404 if (is_scalar) {
12405 if (!is_q) {
12406 unallocated_encoding(s);
12407 return;
12408 }
12409 /* FRINTxx is only in the vector form */
12410 if (only_in_vector) {
12411 unallocated_encoding(s);
12412 return;
12413 }
12414 }
12415
12416 if (!fp_access_check(s)) {
12417 return;
12418 }
12419
15f8a233 12420 if (need_rmode || need_fpst) {
6109aea2
AB
12421 tcg_fpstatus = get_fpstatus_ptr(true);
12422 }
12423
12424 if (need_rmode) {
12425 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
12426 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
12427 }
12428
12429 if (is_scalar) {
3d99d931 12430 TCGv_i32 tcg_op = read_fp_hreg(s, rn);
2df58130
AB
12431 TCGv_i32 tcg_res = tcg_temp_new_i32();
12432
2df58130
AB
12433 switch (fpop) {
12434 case 0x1a: /* FCVTNS */
12435 case 0x1b: /* FCVTMS */
12436 case 0x1c: /* FCVTAS */
12437 case 0x3a: /* FCVTPS */
12438 case 0x3b: /* FCVTZS */
12439 gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
12440 break;
fbd06e1e
AB
12441 case 0x3d: /* FRECPE */
12442 gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
12443 break;
98695028
AB
12444 case 0x3f: /* FRECPX */
12445 gen_helper_frecpx_f16(tcg_res, tcg_op, tcg_fpstatus);
12446 break;
2df58130
AB
12447 case 0x5a: /* FCVTNU */
12448 case 0x5b: /* FCVTMU */
12449 case 0x5c: /* FCVTAU */
12450 case 0x7a: /* FCVTPU */
12451 case 0x7b: /* FCVTZU */
12452 gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
12453 break;
15f8a233
AB
12454 case 0x6f: /* FNEG */
12455 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
12456 break;
c625ff95
AB
12457 case 0x7d: /* FRSQRTE */
12458 gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
12459 break;
2df58130
AB
12460 default:
12461 g_assert_not_reached();
12462 }
12463
12464 /* limit any sign extension going on */
12465 tcg_gen_andi_i32(tcg_res, tcg_res, 0xffff);
12466 write_fp_sreg(s, rd, tcg_res);
12467
12468 tcg_temp_free_i32(tcg_res);
12469 tcg_temp_free_i32(tcg_op);
6109aea2
AB
12470 } else {
12471 for (pass = 0; pass < (is_q ? 8 : 4); pass++) {
12472 TCGv_i32 tcg_op = tcg_temp_new_i32();
12473 TCGv_i32 tcg_res = tcg_temp_new_i32();
12474
12475 read_vec_element_i32(s, tcg_op, rn, pass, MO_16);
12476
12477 switch (fpop) {
2df58130
AB
12478 case 0x1a: /* FCVTNS */
12479 case 0x1b: /* FCVTMS */
12480 case 0x1c: /* FCVTAS */
12481 case 0x3a: /* FCVTPS */
12482 case 0x3b: /* FCVTZS */
12483 gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
12484 break;
fbd06e1e
AB
12485 case 0x3d: /* FRECPE */
12486 gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
12487 break;
2df58130
AB
12488 case 0x5a: /* FCVTNU */
12489 case 0x5b: /* FCVTMU */
12490 case 0x5c: /* FCVTAU */
12491 case 0x7a: /* FCVTPU */
12492 case 0x7b: /* FCVTZU */
12493 gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
12494 break;
6109aea2
AB
12495 case 0x18: /* FRINTN */
12496 case 0x19: /* FRINTM */
12497 case 0x38: /* FRINTP */
12498 case 0x39: /* FRINTZ */
12499 case 0x58: /* FRINTA */
12500 case 0x79: /* FRINTI */
12501 gen_helper_advsimd_rinth(tcg_res, tcg_op, tcg_fpstatus);
12502 break;
12503 case 0x59: /* FRINTX */
12504 gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, tcg_fpstatus);
12505 break;
15f8a233
AB
12506 case 0x2f: /* FABS */
12507 tcg_gen_andi_i32(tcg_res, tcg_op, 0x7fff);
12508 break;
12509 case 0x6f: /* FNEG */
12510 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
12511 break;
c625ff95
AB
12512 case 0x7d: /* FRSQRTE */
12513 gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
12514 break;
b96a54c7
AB
12515 case 0x7f: /* FSQRT */
12516 gen_helper_sqrt_f16(tcg_res, tcg_op, tcg_fpstatus);
12517 break;
6109aea2
AB
12518 default:
12519 g_assert_not_reached();
12520 }
12521
12522 write_vec_element_i32(s, tcg_res, rd, pass, MO_16);
12523
12524 tcg_temp_free_i32(tcg_res);
12525 tcg_temp_free_i32(tcg_op);
12526 }
12527
12528 clear_vec_high(s, is_q, rd);
12529 }
12530
12531 if (tcg_rmode) {
12532 gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
12533 tcg_temp_free_i32(tcg_rmode);
12534 }
12535
12536 if (tcg_fpstatus) {
12537 tcg_temp_free_ptr(tcg_fpstatus);
12538 }
5d432be6
AB
12539}
12540
4ce31af4 12541/* AdvSIMD scalar x indexed element
9f82e0ff
PM
12542 * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
12543 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
12544 * | 0 1 | U | 1 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
12545 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
4ce31af4 12546 * AdvSIMD vector x indexed element
384b26fb
AB
12547 * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
12548 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
12549 * | 0 | Q | U | 0 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
12550 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
12551 */
9f82e0ff 12552static void disas_simd_indexed(DisasContext *s, uint32_t insn)
384b26fb 12553{
f5e51e7f
PM
12554 /* This encoding has two kinds of instruction:
12555 * normal, where we perform elt x idxelt => elt for each
12556 * element in the vector
12557 * long, where we perform elt x idxelt and generate a result of
12558 * double the width of the input element
12559 * The long ops have a 'part' specifier (ie come in INSN, INSN2 pairs).
12560 */
9f82e0ff 12561 bool is_scalar = extract32(insn, 28, 1);
f5e51e7f
PM
12562 bool is_q = extract32(insn, 30, 1);
12563 bool u = extract32(insn, 29, 1);
12564 int size = extract32(insn, 22, 2);
12565 int l = extract32(insn, 21, 1);
12566 int m = extract32(insn, 20, 1);
12567 /* Note that the Rm field here is only 4 bits, not 5 as it usually is */
12568 int rm = extract32(insn, 16, 4);
12569 int opcode = extract32(insn, 12, 4);
12570 int h = extract32(insn, 11, 1);
12571 int rn = extract32(insn, 5, 5);
12572 int rd = extract32(insn, 0, 5);
12573 bool is_long = false;
d17b7cdc 12574 int is_fp = 0;
5d265064 12575 bool is_fp16 = false;
f5e51e7f
PM
12576 int index;
12577 TCGv_ptr fpst;
12578
5f81b1de
RH
12579 switch (16 * u + opcode) {
12580 case 0x08: /* MUL */
12581 case 0x10: /* MLA */
12582 case 0x14: /* MLS */
12583 if (is_scalar) {
f5e51e7f
PM
12584 unallocated_encoding(s);
12585 return;
12586 }
12587 break;
5f81b1de
RH
12588 case 0x02: /* SMLAL, SMLAL2 */
12589 case 0x12: /* UMLAL, UMLAL2 */
12590 case 0x06: /* SMLSL, SMLSL2 */
12591 case 0x16: /* UMLSL, UMLSL2 */
12592 case 0x0a: /* SMULL, SMULL2 */
12593 case 0x1a: /* UMULL, UMULL2 */
9f82e0ff
PM
12594 if (is_scalar) {
12595 unallocated_encoding(s);
12596 return;
12597 }
f5e51e7f
PM
12598 is_long = true;
12599 break;
5f81b1de
RH
12600 case 0x03: /* SQDMLAL, SQDMLAL2 */
12601 case 0x07: /* SQDMLSL, SQDMLSL2 */
12602 case 0x0b: /* SQDMULL, SQDMULL2 */
f5e51e7f 12603 is_long = true;
f5e51e7f 12604 break;
5f81b1de
RH
12605 case 0x0c: /* SQDMULH */
12606 case 0x0d: /* SQRDMULH */
9f82e0ff 12607 break;
5f81b1de
RH
12608 case 0x01: /* FMLA */
12609 case 0x05: /* FMLS */
12610 case 0x09: /* FMUL */
12611 case 0x19: /* FMULX */
d17b7cdc 12612 is_fp = 1;
f5e51e7f 12613 break;
d345df7a
RH
12614 case 0x1d: /* SQRDMLAH */
12615 case 0x1f: /* SQRDMLSH */
962fcbf2 12616 if (!dc_isar_feature(aa64_rdm, s)) {
d345df7a
RH
12617 unallocated_encoding(s);
12618 return;
12619 }
12620 break;
26c470a7
RH
12621 case 0x0e: /* SDOT */
12622 case 0x1e: /* UDOT */
962fcbf2 12623 if (size != MO_32 || !dc_isar_feature(aa64_dp, s)) {
26c470a7
RH
12624 unallocated_encoding(s);
12625 return;
12626 }
12627 break;
d17b7cdc
RH
12628 case 0x11: /* FCMLA #0 */
12629 case 0x13: /* FCMLA #90 */
12630 case 0x15: /* FCMLA #180 */
12631 case 0x17: /* FCMLA #270 */
962fcbf2 12632 if (!dc_isar_feature(aa64_fcma, s)) {
d17b7cdc
RH
12633 unallocated_encoding(s);
12634 return;
12635 }
12636 is_fp = 2;
12637 break;
f5e51e7f
PM
12638 default:
12639 unallocated_encoding(s);
12640 return;
12641 }
12642
d17b7cdc
RH
12643 switch (is_fp) {
12644 case 1: /* normal fp */
5d265064
AB
12645 /* convert insn encoded size to TCGMemOp size */
12646 switch (size) {
449f264b 12647 case 0: /* half-precision */
5d265064 12648 size = MO_16;
d17b7cdc 12649 is_fp16 = true;
449f264b
RH
12650 break;
12651 case MO_32: /* single precision */
12652 case MO_64: /* double precision */
12653 break;
12654 default:
5d265064
AB
12655 unallocated_encoding(s);
12656 return;
f5e51e7f 12657 }
d17b7cdc
RH
12658 break;
12659
12660 case 2: /* complex fp */
12661 /* Each indexable element is a complex pair. */
12662 size <<= 1;
12663 switch (size) {
12664 case MO_32:
12665 if (h && !is_q) {
12666 unallocated_encoding(s);
12667 return;
12668 }
12669 is_fp16 = true;
12670 break;
12671 case MO_64:
12672 break;
12673 default:
12674 unallocated_encoding(s);
12675 return;
12676 }
12677 break;
12678
12679 default: /* integer */
f5e51e7f 12680 switch (size) {
449f264b
RH
12681 case MO_8:
12682 case MO_64:
f5e51e7f
PM
12683 unallocated_encoding(s);
12684 return;
12685 }
d17b7cdc
RH
12686 break;
12687 }
5763190f 12688 if (is_fp16 && !dc_isar_feature(aa64_fp16, s)) {
d17b7cdc
RH
12689 unallocated_encoding(s);
12690 return;
f5e51e7f
PM
12691 }
12692
449f264b
RH
12693 /* Given TCGMemOp size, adjust register and indexing. */
12694 switch (size) {
12695 case MO_16:
12696 index = h << 2 | l << 1 | m;
12697 break;
12698 case MO_32:
12699 index = h << 1 | l;
12700 rm |= m << 4;
12701 break;
12702 case MO_64:
12703 if (l || !is_q) {
12704 unallocated_encoding(s);
12705 return;
12706 }
12707 index = h;
12708 rm |= m << 4;
12709 break;
12710 default:
12711 g_assert_not_reached();
12712 }
12713
8c6afa6a
PM
12714 if (!fp_access_check(s)) {
12715 return;
12716 }
12717
f5e51e7f 12718 if (is_fp) {
5d265064 12719 fpst = get_fpstatus_ptr(is_fp16);
f5e51e7f 12720 } else {
f764718d 12721 fpst = NULL;
f5e51e7f
PM
12722 }
12723
d17b7cdc 12724 switch (16 * u + opcode) {
26c470a7
RH
12725 case 0x0e: /* SDOT */
12726 case 0x1e: /* UDOT */
12727 gen_gvec_op3_ool(s, is_q, rd, rn, rm, index,
12728 u ? gen_helper_gvec_udot_idx_b
12729 : gen_helper_gvec_sdot_idx_b);
12730 return;
d17b7cdc
RH
12731 case 0x11: /* FCMLA #0 */
12732 case 0x13: /* FCMLA #90 */
12733 case 0x15: /* FCMLA #180 */
12734 case 0x17: /* FCMLA #270 */
2cc99919
RH
12735 {
12736 int rot = extract32(insn, 13, 2);
12737 int data = (index << 2) | rot;
12738 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
12739 vec_full_reg_offset(s, rn),
12740 vec_full_reg_offset(s, rm), fpst,
12741 is_q ? 16 : 8, vec_full_reg_size(s), data,
12742 size == MO_64
12743 ? gen_helper_gvec_fcmlas_idx
12744 : gen_helper_gvec_fcmlah_idx);
12745 tcg_temp_free_ptr(fpst);
12746 }
d17b7cdc
RH
12747 return;
12748 }
12749
f5e51e7f
PM
12750 if (size == 3) {
12751 TCGv_i64 tcg_idx = tcg_temp_new_i64();
12752 int pass;
12753
12754 assert(is_fp && is_q && !is_long);
12755
12756 read_vec_element(s, tcg_idx, rm, index, MO_64);
12757
9f82e0ff 12758 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
f5e51e7f
PM
12759 TCGv_i64 tcg_op = tcg_temp_new_i64();
12760 TCGv_i64 tcg_res = tcg_temp_new_i64();
12761
12762 read_vec_element(s, tcg_op, rn, pass, MO_64);
12763
5f81b1de
RH
12764 switch (16 * u + opcode) {
12765 case 0x05: /* FMLS */
f5e51e7f
PM
12766 /* As usual for ARM, separate negation for fused multiply-add */
12767 gen_helper_vfp_negd(tcg_op, tcg_op);
12768 /* fall through */
5f81b1de 12769 case 0x01: /* FMLA */
f5e51e7f
PM
12770 read_vec_element(s, tcg_res, rd, pass, MO_64);
12771 gen_helper_vfp_muladdd(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
12772 break;
5f81b1de
RH
12773 case 0x09: /* FMUL */
12774 gen_helper_vfp_muld(tcg_res, tcg_op, tcg_idx, fpst);
12775 break;
12776 case 0x19: /* FMULX */
12777 gen_helper_vfp_mulxd(tcg_res, tcg_op, tcg_idx, fpst);
f5e51e7f
PM
12778 break;
12779 default:
12780 g_assert_not_reached();
12781 }
12782
12783 write_vec_element(s, tcg_res, rd, pass, MO_64);
12784 tcg_temp_free_i64(tcg_op);
12785 tcg_temp_free_i64(tcg_res);
12786 }
12787
12788 tcg_temp_free_i64(tcg_idx);
4ff55bcb 12789 clear_vec_high(s, !is_scalar, rd);
f5e51e7f 12790 } else if (!is_long) {
9f82e0ff
PM
12791 /* 32 bit floating point, or 16 or 32 bit integer.
12792 * For the 16 bit scalar case we use the usual Neon helpers and
12793 * rely on the fact that 0 op 0 == 0 with no side effects.
12794 */
f5e51e7f 12795 TCGv_i32 tcg_idx = tcg_temp_new_i32();
9f82e0ff
PM
12796 int pass, maxpasses;
12797
12798 if (is_scalar) {
12799 maxpasses = 1;
12800 } else {
12801 maxpasses = is_q ? 4 : 2;
12802 }
f5e51e7f
PM
12803
12804 read_vec_element_i32(s, tcg_idx, rm, index, size);
12805
9f82e0ff 12806 if (size == 1 && !is_scalar) {
f5e51e7f
PM
12807 /* The simplest way to handle the 16x16 indexed ops is to duplicate
12808 * the index into both halves of the 32 bit tcg_idx and then use
12809 * the usual Neon helpers.
12810 */
12811 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
12812 }
12813
9f82e0ff 12814 for (pass = 0; pass < maxpasses; pass++) {
f5e51e7f
PM
12815 TCGv_i32 tcg_op = tcg_temp_new_i32();
12816 TCGv_i32 tcg_res = tcg_temp_new_i32();
12817
9f82e0ff 12818 read_vec_element_i32(s, tcg_op, rn, pass, is_scalar ? size : MO_32);
f5e51e7f 12819
5f81b1de
RH
12820 switch (16 * u + opcode) {
12821 case 0x08: /* MUL */
12822 case 0x10: /* MLA */
12823 case 0x14: /* MLS */
f5e51e7f
PM
12824 {
12825 static NeonGenTwoOpFn * const fns[2][2] = {
12826 { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
12827 { tcg_gen_add_i32, tcg_gen_sub_i32 },
12828 };
12829 NeonGenTwoOpFn *genfn;
12830 bool is_sub = opcode == 0x4;
12831
12832 if (size == 1) {
12833 gen_helper_neon_mul_u16(tcg_res, tcg_op, tcg_idx);
12834 } else {
12835 tcg_gen_mul_i32(tcg_res, tcg_op, tcg_idx);
12836 }
12837 if (opcode == 0x8) {
12838 break;
12839 }
12840 read_vec_element_i32(s, tcg_op, rd, pass, MO_32);
12841 genfn = fns[size - 1][is_sub];
12842 genfn(tcg_res, tcg_op, tcg_res);
12843 break;
12844 }
5f81b1de
RH
12845 case 0x05: /* FMLS */
12846 case 0x01: /* FMLA */
5d265064
AB
12847 read_vec_element_i32(s, tcg_res, rd, pass,
12848 is_scalar ? size : MO_32);
12849 switch (size) {
12850 case 1:
12851 if (opcode == 0x5) {
12852 /* As usual for ARM, separate negation for fused
12853 * multiply-add */
12854 tcg_gen_xori_i32(tcg_op, tcg_op, 0x80008000);
12855 }
6089030c
AB
12856 if (is_scalar) {
12857 gen_helper_advsimd_muladdh(tcg_res, tcg_op, tcg_idx,
12858 tcg_res, fpst);
12859 } else {
12860 gen_helper_advsimd_muladd2h(tcg_res, tcg_op, tcg_idx,
12861 tcg_res, fpst);
12862 }
5d265064
AB
12863 break;
12864 case 2:
12865 if (opcode == 0x5) {
12866 /* As usual for ARM, separate negation for
12867 * fused multiply-add */
12868 tcg_gen_xori_i32(tcg_op, tcg_op, 0x80000000);
12869 }
12870 gen_helper_vfp_muladds(tcg_res, tcg_op, tcg_idx,
12871 tcg_res, fpst);
12872 break;
12873 default:
12874 g_assert_not_reached();
12875 }
f5e51e7f 12876 break;
5f81b1de 12877 case 0x09: /* FMUL */
5d265064
AB
12878 switch (size) {
12879 case 1:
5f81b1de
RH
12880 if (is_scalar) {
12881 gen_helper_advsimd_mulh(tcg_res, tcg_op,
12882 tcg_idx, fpst);
5d265064 12883 } else {
5f81b1de
RH
12884 gen_helper_advsimd_mul2h(tcg_res, tcg_op,
12885 tcg_idx, fpst);
5d265064
AB
12886 }
12887 break;
12888 case 2:
5f81b1de
RH
12889 gen_helper_vfp_muls(tcg_res, tcg_op, tcg_idx, fpst);
12890 break;
12891 default:
12892 g_assert_not_reached();
12893 }
12894 break;
12895 case 0x19: /* FMULX */
12896 switch (size) {
12897 case 1:
12898 if (is_scalar) {
12899 gen_helper_advsimd_mulxh(tcg_res, tcg_op,
12900 tcg_idx, fpst);
5d265064 12901 } else {
5f81b1de
RH
12902 gen_helper_advsimd_mulx2h(tcg_res, tcg_op,
12903 tcg_idx, fpst);
5d265064
AB
12904 }
12905 break;
5f81b1de
RH
12906 case 2:
12907 gen_helper_vfp_mulxs(tcg_res, tcg_op, tcg_idx, fpst);
12908 break;
5d265064
AB
12909 default:
12910 g_assert_not_reached();
f5e51e7f
PM
12911 }
12912 break;
5f81b1de 12913 case 0x0c: /* SQDMULH */
f5e51e7f
PM
12914 if (size == 1) {
12915 gen_helper_neon_qdmulh_s16(tcg_res, cpu_env,
12916 tcg_op, tcg_idx);
12917 } else {
12918 gen_helper_neon_qdmulh_s32(tcg_res, cpu_env,
12919 tcg_op, tcg_idx);
12920 }
12921 break;
5f81b1de 12922 case 0x0d: /* SQRDMULH */
f5e51e7f
PM
12923 if (size == 1) {
12924 gen_helper_neon_qrdmulh_s16(tcg_res, cpu_env,
12925 tcg_op, tcg_idx);
12926 } else {
12927 gen_helper_neon_qrdmulh_s32(tcg_res, cpu_env,
12928 tcg_op, tcg_idx);
12929 }
12930 break;
d345df7a
RH
12931 case 0x1d: /* SQRDMLAH */
12932 read_vec_element_i32(s, tcg_res, rd, pass,
12933 is_scalar ? size : MO_32);
12934 if (size == 1) {
12935 gen_helper_neon_qrdmlah_s16(tcg_res, cpu_env,
12936 tcg_op, tcg_idx, tcg_res);
12937 } else {
12938 gen_helper_neon_qrdmlah_s32(tcg_res, cpu_env,
12939 tcg_op, tcg_idx, tcg_res);
12940 }
12941 break;
12942 case 0x1f: /* SQRDMLSH */
12943 read_vec_element_i32(s, tcg_res, rd, pass,
12944 is_scalar ? size : MO_32);
12945 if (size == 1) {
12946 gen_helper_neon_qrdmlsh_s16(tcg_res, cpu_env,
12947 tcg_op, tcg_idx, tcg_res);
12948 } else {
12949 gen_helper_neon_qrdmlsh_s32(tcg_res, cpu_env,
12950 tcg_op, tcg_idx, tcg_res);
12951 }
12952 break;
f5e51e7f
PM
12953 default:
12954 g_assert_not_reached();
12955 }
12956
9f82e0ff
PM
12957 if (is_scalar) {
12958 write_fp_sreg(s, rd, tcg_res);
12959 } else {
12960 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
12961 }
12962
f5e51e7f
PM
12963 tcg_temp_free_i32(tcg_op);
12964 tcg_temp_free_i32(tcg_res);
12965 }
12966
12967 tcg_temp_free_i32(tcg_idx);
4ff55bcb 12968 clear_vec_high(s, is_q, rd);
f5e51e7f
PM
12969 } else {
12970 /* long ops: 16x16->32 or 32x32->64 */
c44ad1fd
PM
12971 TCGv_i64 tcg_res[2];
12972 int pass;
12973 bool satop = extract32(opcode, 0, 1);
12974 TCGMemOp memop = MO_32;
12975
12976 if (satop || !u) {
12977 memop |= MO_SIGN;
12978 }
12979
12980 if (size == 2) {
12981 TCGv_i64 tcg_idx = tcg_temp_new_i64();
12982
12983 read_vec_element(s, tcg_idx, rm, index, memop);
12984
9f82e0ff 12985 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
c44ad1fd
PM
12986 TCGv_i64 tcg_op = tcg_temp_new_i64();
12987 TCGv_i64 tcg_passres;
9f82e0ff 12988 int passelt;
c44ad1fd 12989
9f82e0ff
PM
12990 if (is_scalar) {
12991 passelt = 0;
12992 } else {
12993 passelt = pass + (is_q * 2);
12994 }
12995
12996 read_vec_element(s, tcg_op, rn, passelt, memop);
c44ad1fd
PM
12997
12998 tcg_res[pass] = tcg_temp_new_i64();
12999
13000 if (opcode == 0xa || opcode == 0xb) {
13001 /* Non-accumulating ops */
13002 tcg_passres = tcg_res[pass];
13003 } else {
13004 tcg_passres = tcg_temp_new_i64();
13005 }
13006
13007 tcg_gen_mul_i64(tcg_passres, tcg_op, tcg_idx);
13008 tcg_temp_free_i64(tcg_op);
13009
13010 if (satop) {
13011 /* saturating, doubling */
13012 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
13013 tcg_passres, tcg_passres);
13014 }
13015
13016 if (opcode == 0xa || opcode == 0xb) {
13017 continue;
13018 }
13019
13020 /* Accumulating op: handle accumulate step */
13021 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13022
13023 switch (opcode) {
13024 case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
13025 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
13026 break;
13027 case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
13028 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
13029 break;
13030 case 0x7: /* SQDMLSL, SQDMLSL2 */
13031 tcg_gen_neg_i64(tcg_passres, tcg_passres);
13032 /* fall through */
13033 case 0x3: /* SQDMLAL, SQDMLAL2 */
13034 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
13035 tcg_res[pass],
13036 tcg_passres);
13037 break;
13038 default:
13039 g_assert_not_reached();
13040 }
13041 tcg_temp_free_i64(tcg_passres);
13042 }
13043 tcg_temp_free_i64(tcg_idx);
9f82e0ff 13044
4ff55bcb 13045 clear_vec_high(s, !is_scalar, rd);
c44ad1fd
PM
13046 } else {
13047 TCGv_i32 tcg_idx = tcg_temp_new_i32();
13048
13049 assert(size == 1);
13050 read_vec_element_i32(s, tcg_idx, rm, index, size);
13051
9f82e0ff
PM
13052 if (!is_scalar) {
13053 /* The simplest way to handle the 16x16 indexed ops is to
13054 * duplicate the index into both halves of the 32 bit tcg_idx
13055 * and then use the usual Neon helpers.
13056 */
13057 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
13058 }
c44ad1fd 13059
9f82e0ff 13060 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
c44ad1fd
PM
13061 TCGv_i32 tcg_op = tcg_temp_new_i32();
13062 TCGv_i64 tcg_passres;
13063
9f82e0ff
PM
13064 if (is_scalar) {
13065 read_vec_element_i32(s, tcg_op, rn, pass, size);
13066 } else {
13067 read_vec_element_i32(s, tcg_op, rn,
13068 pass + (is_q * 2), MO_32);
13069 }
13070
c44ad1fd
PM
13071 tcg_res[pass] = tcg_temp_new_i64();
13072
13073 if (opcode == 0xa || opcode == 0xb) {
13074 /* Non-accumulating ops */
13075 tcg_passres = tcg_res[pass];
13076 } else {
13077 tcg_passres = tcg_temp_new_i64();
13078 }
13079
13080 if (memop & MO_SIGN) {
13081 gen_helper_neon_mull_s16(tcg_passres, tcg_op, tcg_idx);
13082 } else {
13083 gen_helper_neon_mull_u16(tcg_passres, tcg_op, tcg_idx);
13084 }
13085 if (satop) {
13086 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
13087 tcg_passres, tcg_passres);
13088 }
13089 tcg_temp_free_i32(tcg_op);
13090
13091 if (opcode == 0xa || opcode == 0xb) {
13092 continue;
13093 }
13094
13095 /* Accumulating op: handle accumulate step */
13096 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13097
13098 switch (opcode) {
13099 case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
13100 gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
13101 tcg_passres);
13102 break;
13103 case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
13104 gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
13105 tcg_passres);
13106 break;
13107 case 0x7: /* SQDMLSL, SQDMLSL2 */
13108 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
13109 /* fall through */
13110 case 0x3: /* SQDMLAL, SQDMLAL2 */
13111 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
13112 tcg_res[pass],
13113 tcg_passres);
13114 break;
13115 default:
13116 g_assert_not_reached();
13117 }
13118 tcg_temp_free_i64(tcg_passres);
13119 }
13120 tcg_temp_free_i32(tcg_idx);
9f82e0ff
PM
13121
13122 if (is_scalar) {
13123 tcg_gen_ext32u_i64(tcg_res[0], tcg_res[0]);
13124 }
13125 }
13126
13127 if (is_scalar) {
13128 tcg_res[1] = tcg_const_i64(0);
c44ad1fd
PM
13129 }
13130
13131 for (pass = 0; pass < 2; pass++) {
13132 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13133 tcg_temp_free_i64(tcg_res[pass]);
13134 }
f5e51e7f
PM
13135 }
13136
f764718d 13137 if (fpst) {
f5e51e7f
PM
13138 tcg_temp_free_ptr(fpst);
13139 }
384b26fb
AB
13140}
13141
4ce31af4 13142/* Crypto AES
384b26fb
AB
13143 * 31 24 23 22 21 17 16 12 11 10 9 5 4 0
13144 * +-----------------+------+-----------+--------+-----+------+------+
13145 * | 0 1 0 0 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
13146 * +-----------------+------+-----------+--------+-----+------+------+
13147 */
13148static void disas_crypto_aes(DisasContext *s, uint32_t insn)
13149{
5acc765c
PM
13150 int size = extract32(insn, 22, 2);
13151 int opcode = extract32(insn, 12, 5);
13152 int rn = extract32(insn, 5, 5);
13153 int rd = extract32(insn, 0, 5);
13154 int decrypt;
1a66ac61
RH
13155 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
13156 TCGv_i32 tcg_decrypt;
13157 CryptoThreeOpIntFn *genfn;
5acc765c 13158
962fcbf2 13159 if (!dc_isar_feature(aa64_aes, s) || size != 0) {
5acc765c
PM
13160 unallocated_encoding(s);
13161 return;
13162 }
13163
13164 switch (opcode) {
13165 case 0x4: /* AESE */
13166 decrypt = 0;
13167 genfn = gen_helper_crypto_aese;
13168 break;
13169 case 0x6: /* AESMC */
13170 decrypt = 0;
13171 genfn = gen_helper_crypto_aesmc;
13172 break;
13173 case 0x5: /* AESD */
13174 decrypt = 1;
13175 genfn = gen_helper_crypto_aese;
13176 break;
13177 case 0x7: /* AESIMC */
13178 decrypt = 1;
13179 genfn = gen_helper_crypto_aesmc;
13180 break;
13181 default:
13182 unallocated_encoding(s);
13183 return;
13184 }
13185
a4f5c5b7
NR
13186 if (!fp_access_check(s)) {
13187 return;
13188 }
13189
1a66ac61
RH
13190 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13191 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
5acc765c
PM
13192 tcg_decrypt = tcg_const_i32(decrypt);
13193
1a66ac61 13194 genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_decrypt);
5acc765c 13195
1a66ac61
RH
13196 tcg_temp_free_ptr(tcg_rd_ptr);
13197 tcg_temp_free_ptr(tcg_rn_ptr);
5acc765c 13198 tcg_temp_free_i32(tcg_decrypt);
384b26fb
AB
13199}
13200
4ce31af4 13201/* Crypto three-reg SHA
384b26fb
AB
13202 * 31 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
13203 * +-----------------+------+---+------+---+--------+-----+------+------+
13204 * | 0 1 0 1 1 1 1 0 | size | 0 | Rm | 0 | opcode | 0 0 | Rn | Rd |
13205 * +-----------------+------+---+------+---+--------+-----+------+------+
13206 */
13207static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
13208{
be56f04e
PM
13209 int size = extract32(insn, 22, 2);
13210 int opcode = extract32(insn, 12, 3);
13211 int rm = extract32(insn, 16, 5);
13212 int rn = extract32(insn, 5, 5);
13213 int rd = extract32(insn, 0, 5);
1a66ac61
RH
13214 CryptoThreeOpFn *genfn;
13215 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
962fcbf2 13216 bool feature;
be56f04e
PM
13217
13218 if (size != 0) {
13219 unallocated_encoding(s);
13220 return;
13221 }
13222
13223 switch (opcode) {
13224 case 0: /* SHA1C */
13225 case 1: /* SHA1P */
13226 case 2: /* SHA1M */
13227 case 3: /* SHA1SU0 */
13228 genfn = NULL;
962fcbf2 13229 feature = dc_isar_feature(aa64_sha1, s);
be56f04e
PM
13230 break;
13231 case 4: /* SHA256H */
13232 genfn = gen_helper_crypto_sha256h;
962fcbf2 13233 feature = dc_isar_feature(aa64_sha256, s);
be56f04e
PM
13234 break;
13235 case 5: /* SHA256H2 */
13236 genfn = gen_helper_crypto_sha256h2;
962fcbf2 13237 feature = dc_isar_feature(aa64_sha256, s);
be56f04e
PM
13238 break;
13239 case 6: /* SHA256SU1 */
13240 genfn = gen_helper_crypto_sha256su1;
962fcbf2 13241 feature = dc_isar_feature(aa64_sha256, s);
be56f04e
PM
13242 break;
13243 default:
13244 unallocated_encoding(s);
13245 return;
13246 }
13247
962fcbf2 13248 if (!feature) {
be56f04e
PM
13249 unallocated_encoding(s);
13250 return;
13251 }
13252
a4f5c5b7
NR
13253 if (!fp_access_check(s)) {
13254 return;
13255 }
13256
1a66ac61
RH
13257 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13258 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
13259 tcg_rm_ptr = vec_full_reg_ptr(s, rm);
be56f04e
PM
13260
13261 if (genfn) {
1a66ac61 13262 genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
be56f04e
PM
13263 } else {
13264 TCGv_i32 tcg_opcode = tcg_const_i32(opcode);
13265
1a66ac61
RH
13266 gen_helper_crypto_sha1_3reg(tcg_rd_ptr, tcg_rn_ptr,
13267 tcg_rm_ptr, tcg_opcode);
be56f04e
PM
13268 tcg_temp_free_i32(tcg_opcode);
13269 }
13270
1a66ac61
RH
13271 tcg_temp_free_ptr(tcg_rd_ptr);
13272 tcg_temp_free_ptr(tcg_rn_ptr);
13273 tcg_temp_free_ptr(tcg_rm_ptr);
384b26fb
AB
13274}
13275
4ce31af4 13276/* Crypto two-reg SHA
384b26fb
AB
13277 * 31 24 23 22 21 17 16 12 11 10 9 5 4 0
13278 * +-----------------+------+-----------+--------+-----+------+------+
13279 * | 0 1 0 1 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
13280 * +-----------------+------+-----------+--------+-----+------+------+
13281 */
13282static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
13283{
f6fe04d5
PM
13284 int size = extract32(insn, 22, 2);
13285 int opcode = extract32(insn, 12, 5);
13286 int rn = extract32(insn, 5, 5);
13287 int rd = extract32(insn, 0, 5);
1a66ac61 13288 CryptoTwoOpFn *genfn;
962fcbf2 13289 bool feature;
1a66ac61 13290 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
f6fe04d5
PM
13291
13292 if (size != 0) {
13293 unallocated_encoding(s);
13294 return;
13295 }
13296
13297 switch (opcode) {
13298 case 0: /* SHA1H */
962fcbf2 13299 feature = dc_isar_feature(aa64_sha1, s);
f6fe04d5
PM
13300 genfn = gen_helper_crypto_sha1h;
13301 break;
13302 case 1: /* SHA1SU1 */
962fcbf2 13303 feature = dc_isar_feature(aa64_sha1, s);
f6fe04d5
PM
13304 genfn = gen_helper_crypto_sha1su1;
13305 break;
13306 case 2: /* SHA256SU0 */
962fcbf2 13307 feature = dc_isar_feature(aa64_sha256, s);
f6fe04d5
PM
13308 genfn = gen_helper_crypto_sha256su0;
13309 break;
13310 default:
13311 unallocated_encoding(s);
13312 return;
13313 }
13314
962fcbf2 13315 if (!feature) {
f6fe04d5
PM
13316 unallocated_encoding(s);
13317 return;
13318 }
13319
a4f5c5b7
NR
13320 if (!fp_access_check(s)) {
13321 return;
13322 }
13323
1a66ac61
RH
13324 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13325 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
f6fe04d5 13326
1a66ac61 13327 genfn(tcg_rd_ptr, tcg_rn_ptr);
f6fe04d5 13328
1a66ac61
RH
13329 tcg_temp_free_ptr(tcg_rd_ptr);
13330 tcg_temp_free_ptr(tcg_rn_ptr);
384b26fb
AB
13331}
13332
90b827d1
AB
13333/* Crypto three-reg SHA512
13334 * 31 21 20 16 15 14 13 12 11 10 9 5 4 0
13335 * +-----------------------+------+---+---+-----+--------+------+------+
13336 * | 1 1 0 0 1 1 1 0 0 1 1 | Rm | 1 | O | 0 0 | opcode | Rn | Rd |
13337 * +-----------------------+------+---+---+-----+--------+------+------+
13338 */
13339static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
13340{
13341 int opcode = extract32(insn, 10, 2);
13342 int o = extract32(insn, 14, 1);
13343 int rm = extract32(insn, 16, 5);
13344 int rn = extract32(insn, 5, 5);
13345 int rd = extract32(insn, 0, 5);
962fcbf2 13346 bool feature;
90b827d1
AB
13347 CryptoThreeOpFn *genfn;
13348
13349 if (o == 0) {
13350 switch (opcode) {
13351 case 0: /* SHA512H */
962fcbf2 13352 feature = dc_isar_feature(aa64_sha512, s);
90b827d1
AB
13353 genfn = gen_helper_crypto_sha512h;
13354 break;
13355 case 1: /* SHA512H2 */
962fcbf2 13356 feature = dc_isar_feature(aa64_sha512, s);
90b827d1
AB
13357 genfn = gen_helper_crypto_sha512h2;
13358 break;
13359 case 2: /* SHA512SU1 */
962fcbf2 13360 feature = dc_isar_feature(aa64_sha512, s);
90b827d1
AB
13361 genfn = gen_helper_crypto_sha512su1;
13362 break;
cd270ade 13363 case 3: /* RAX1 */
962fcbf2 13364 feature = dc_isar_feature(aa64_sha3, s);
cd270ade
AB
13365 genfn = NULL;
13366 break;
90b827d1
AB
13367 }
13368 } else {
80d6f4c6
AB
13369 switch (opcode) {
13370 case 0: /* SM3PARTW1 */
962fcbf2 13371 feature = dc_isar_feature(aa64_sm3, s);
80d6f4c6
AB
13372 genfn = gen_helper_crypto_sm3partw1;
13373 break;
13374 case 1: /* SM3PARTW2 */
962fcbf2 13375 feature = dc_isar_feature(aa64_sm3, s);
80d6f4c6
AB
13376 genfn = gen_helper_crypto_sm3partw2;
13377 break;
b6577bcd 13378 case 2: /* SM4EKEY */
962fcbf2 13379 feature = dc_isar_feature(aa64_sm4, s);
b6577bcd
AB
13380 genfn = gen_helper_crypto_sm4ekey;
13381 break;
80d6f4c6
AB
13382 default:
13383 unallocated_encoding(s);
13384 return;
13385 }
90b827d1
AB
13386 }
13387
962fcbf2 13388 if (!feature) {
90b827d1
AB
13389 unallocated_encoding(s);
13390 return;
13391 }
13392
13393 if (!fp_access_check(s)) {
13394 return;
13395 }
13396
13397 if (genfn) {
13398 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
13399
13400 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13401 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
13402 tcg_rm_ptr = vec_full_reg_ptr(s, rm);
13403
13404 genfn(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr);
13405
13406 tcg_temp_free_ptr(tcg_rd_ptr);
13407 tcg_temp_free_ptr(tcg_rn_ptr);
13408 tcg_temp_free_ptr(tcg_rm_ptr);
13409 } else {
cd270ade
AB
13410 TCGv_i64 tcg_op1, tcg_op2, tcg_res[2];
13411 int pass;
13412
13413 tcg_op1 = tcg_temp_new_i64();
13414 tcg_op2 = tcg_temp_new_i64();
13415 tcg_res[0] = tcg_temp_new_i64();
13416 tcg_res[1] = tcg_temp_new_i64();
13417
13418 for (pass = 0; pass < 2; pass++) {
13419 read_vec_element(s, tcg_op1, rn, pass, MO_64);
13420 read_vec_element(s, tcg_op2, rm, pass, MO_64);
13421
13422 tcg_gen_rotli_i64(tcg_res[pass], tcg_op2, 1);
13423 tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
13424 }
13425 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
13426 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
13427
13428 tcg_temp_free_i64(tcg_op1);
13429 tcg_temp_free_i64(tcg_op2);
13430 tcg_temp_free_i64(tcg_res[0]);
13431 tcg_temp_free_i64(tcg_res[1]);
90b827d1
AB
13432 }
13433}
13434
13435/* Crypto two-reg SHA512
13436 * 31 12 11 10 9 5 4 0
13437 * +-----------------------------------------+--------+------+------+
13438 * | 1 1 0 0 1 1 1 0 1 1 0 0 0 0 0 0 1 0 0 0 | opcode | Rn | Rd |
13439 * +-----------------------------------------+--------+------+------+
13440 */
13441static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn)
13442{
13443 int opcode = extract32(insn, 10, 2);
13444 int rn = extract32(insn, 5, 5);
13445 int rd = extract32(insn, 0, 5);
13446 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr;
962fcbf2 13447 bool feature;
90b827d1
AB
13448 CryptoTwoOpFn *genfn;
13449
13450 switch (opcode) {
13451 case 0: /* SHA512SU0 */
962fcbf2 13452 feature = dc_isar_feature(aa64_sha512, s);
90b827d1
AB
13453 genfn = gen_helper_crypto_sha512su0;
13454 break;
b6577bcd 13455 case 1: /* SM4E */
962fcbf2 13456 feature = dc_isar_feature(aa64_sm4, s);
b6577bcd
AB
13457 genfn = gen_helper_crypto_sm4e;
13458 break;
90b827d1
AB
13459 default:
13460 unallocated_encoding(s);
13461 return;
13462 }
13463
962fcbf2 13464 if (!feature) {
90b827d1
AB
13465 unallocated_encoding(s);
13466 return;
13467 }
13468
13469 if (!fp_access_check(s)) {
13470 return;
13471 }
13472
13473 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13474 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
13475
13476 genfn(tcg_rd_ptr, tcg_rn_ptr);
13477
13478 tcg_temp_free_ptr(tcg_rd_ptr);
13479 tcg_temp_free_ptr(tcg_rn_ptr);
13480}
13481
cd270ade
AB
13482/* Crypto four-register
13483 * 31 23 22 21 20 16 15 14 10 9 5 4 0
13484 * +-------------------+-----+------+---+------+------+------+
13485 * | 1 1 0 0 1 1 1 0 0 | Op0 | Rm | 0 | Ra | Rn | Rd |
13486 * +-------------------+-----+------+---+------+------+------+
13487 */
13488static void disas_crypto_four_reg(DisasContext *s, uint32_t insn)
13489{
13490 int op0 = extract32(insn, 21, 2);
13491 int rm = extract32(insn, 16, 5);
13492 int ra = extract32(insn, 10, 5);
13493 int rn = extract32(insn, 5, 5);
13494 int rd = extract32(insn, 0, 5);
962fcbf2 13495 bool feature;
cd270ade
AB
13496
13497 switch (op0) {
13498 case 0: /* EOR3 */
13499 case 1: /* BCAX */
962fcbf2 13500 feature = dc_isar_feature(aa64_sha3, s);
cd270ade 13501 break;
80d6f4c6 13502 case 2: /* SM3SS1 */
962fcbf2 13503 feature = dc_isar_feature(aa64_sm3, s);
80d6f4c6 13504 break;
cd270ade
AB
13505 default:
13506 unallocated_encoding(s);
13507 return;
13508 }
13509
962fcbf2 13510 if (!feature) {
cd270ade
AB
13511 unallocated_encoding(s);
13512 return;
13513 }
13514
13515 if (!fp_access_check(s)) {
13516 return;
13517 }
13518
13519 if (op0 < 2) {
13520 TCGv_i64 tcg_op1, tcg_op2, tcg_op3, tcg_res[2];
13521 int pass;
13522
13523 tcg_op1 = tcg_temp_new_i64();
13524 tcg_op2 = tcg_temp_new_i64();
13525 tcg_op3 = tcg_temp_new_i64();
13526 tcg_res[0] = tcg_temp_new_i64();
13527 tcg_res[1] = tcg_temp_new_i64();
13528
13529 for (pass = 0; pass < 2; pass++) {
13530 read_vec_element(s, tcg_op1, rn, pass, MO_64);
13531 read_vec_element(s, tcg_op2, rm, pass, MO_64);
13532 read_vec_element(s, tcg_op3, ra, pass, MO_64);
13533
13534 if (op0 == 0) {
13535 /* EOR3 */
13536 tcg_gen_xor_i64(tcg_res[pass], tcg_op2, tcg_op3);
13537 } else {
13538 /* BCAX */
13539 tcg_gen_andc_i64(tcg_res[pass], tcg_op2, tcg_op3);
13540 }
13541 tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
13542 }
13543 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
13544 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
13545
13546 tcg_temp_free_i64(tcg_op1);
13547 tcg_temp_free_i64(tcg_op2);
13548 tcg_temp_free_i64(tcg_op3);
13549 tcg_temp_free_i64(tcg_res[0]);
13550 tcg_temp_free_i64(tcg_res[1]);
13551 } else {
80d6f4c6
AB
13552 TCGv_i32 tcg_op1, tcg_op2, tcg_op3, tcg_res, tcg_zero;
13553
13554 tcg_op1 = tcg_temp_new_i32();
13555 tcg_op2 = tcg_temp_new_i32();
13556 tcg_op3 = tcg_temp_new_i32();
13557 tcg_res = tcg_temp_new_i32();
13558 tcg_zero = tcg_const_i32(0);
13559
13560 read_vec_element_i32(s, tcg_op1, rn, 3, MO_32);
13561 read_vec_element_i32(s, tcg_op2, rm, 3, MO_32);
13562 read_vec_element_i32(s, tcg_op3, ra, 3, MO_32);
13563
13564 tcg_gen_rotri_i32(tcg_res, tcg_op1, 20);
13565 tcg_gen_add_i32(tcg_res, tcg_res, tcg_op2);
13566 tcg_gen_add_i32(tcg_res, tcg_res, tcg_op3);
13567 tcg_gen_rotri_i32(tcg_res, tcg_res, 25);
13568
13569 write_vec_element_i32(s, tcg_zero, rd, 0, MO_32);
13570 write_vec_element_i32(s, tcg_zero, rd, 1, MO_32);
13571 write_vec_element_i32(s, tcg_zero, rd, 2, MO_32);
13572 write_vec_element_i32(s, tcg_res, rd, 3, MO_32);
13573
13574 tcg_temp_free_i32(tcg_op1);
13575 tcg_temp_free_i32(tcg_op2);
13576 tcg_temp_free_i32(tcg_op3);
13577 tcg_temp_free_i32(tcg_res);
13578 tcg_temp_free_i32(tcg_zero);
cd270ade
AB
13579 }
13580}
13581
13582/* Crypto XAR
13583 * 31 21 20 16 15 10 9 5 4 0
13584 * +-----------------------+------+--------+------+------+
13585 * | 1 1 0 0 1 1 1 0 1 0 0 | Rm | imm6 | Rn | Rd |
13586 * +-----------------------+------+--------+------+------+
13587 */
13588static void disas_crypto_xar(DisasContext *s, uint32_t insn)
13589{
13590 int rm = extract32(insn, 16, 5);
13591 int imm6 = extract32(insn, 10, 6);
13592 int rn = extract32(insn, 5, 5);
13593 int rd = extract32(insn, 0, 5);
13594 TCGv_i64 tcg_op1, tcg_op2, tcg_res[2];
13595 int pass;
13596
962fcbf2 13597 if (!dc_isar_feature(aa64_sha3, s)) {
cd270ade
AB
13598 unallocated_encoding(s);
13599 return;
13600 }
13601
13602 if (!fp_access_check(s)) {
13603 return;
13604 }
13605
13606 tcg_op1 = tcg_temp_new_i64();
13607 tcg_op2 = tcg_temp_new_i64();
13608 tcg_res[0] = tcg_temp_new_i64();
13609 tcg_res[1] = tcg_temp_new_i64();
13610
13611 for (pass = 0; pass < 2; pass++) {
13612 read_vec_element(s, tcg_op1, rn, pass, MO_64);
13613 read_vec_element(s, tcg_op2, rm, pass, MO_64);
13614
13615 tcg_gen_xor_i64(tcg_res[pass], tcg_op1, tcg_op2);
13616 tcg_gen_rotri_i64(tcg_res[pass], tcg_res[pass], imm6);
13617 }
13618 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
13619 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
13620
13621 tcg_temp_free_i64(tcg_op1);
13622 tcg_temp_free_i64(tcg_op2);
13623 tcg_temp_free_i64(tcg_res[0]);
13624 tcg_temp_free_i64(tcg_res[1]);
13625}
13626
80d6f4c6
AB
13627/* Crypto three-reg imm2
13628 * 31 21 20 16 15 14 13 12 11 10 9 5 4 0
13629 * +-----------------------+------+-----+------+--------+------+------+
13630 * | 1 1 0 0 1 1 1 0 0 1 0 | Rm | 1 0 | imm2 | opcode | Rn | Rd |
13631 * +-----------------------+------+-----+------+--------+------+------+
13632 */
13633static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn)
13634{
13635 int opcode = extract32(insn, 10, 2);
13636 int imm2 = extract32(insn, 12, 2);
13637 int rm = extract32(insn, 16, 5);
13638 int rn = extract32(insn, 5, 5);
13639 int rd = extract32(insn, 0, 5);
13640 TCGv_ptr tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr;
13641 TCGv_i32 tcg_imm2, tcg_opcode;
13642
962fcbf2 13643 if (!dc_isar_feature(aa64_sm3, s)) {
80d6f4c6
AB
13644 unallocated_encoding(s);
13645 return;
13646 }
13647
13648 if (!fp_access_check(s)) {
13649 return;
13650 }
13651
13652 tcg_rd_ptr = vec_full_reg_ptr(s, rd);
13653 tcg_rn_ptr = vec_full_reg_ptr(s, rn);
13654 tcg_rm_ptr = vec_full_reg_ptr(s, rm);
13655 tcg_imm2 = tcg_const_i32(imm2);
13656 tcg_opcode = tcg_const_i32(opcode);
13657
13658 gen_helper_crypto_sm3tt(tcg_rd_ptr, tcg_rn_ptr, tcg_rm_ptr, tcg_imm2,
13659 tcg_opcode);
13660
13661 tcg_temp_free_ptr(tcg_rd_ptr);
13662 tcg_temp_free_ptr(tcg_rn_ptr);
13663 tcg_temp_free_ptr(tcg_rm_ptr);
13664 tcg_temp_free_i32(tcg_imm2);
13665 tcg_temp_free_i32(tcg_opcode);
13666}
13667
384b26fb
AB
13668/* C3.6 Data processing - SIMD, inc Crypto
13669 *
13670 * As the decode gets a little complex we are using a table based
13671 * approach for this part of the decode.
13672 */
13673static const AArch64DecodeTable data_proc_simd[] = {
13674 /* pattern , mask , fn */
13675 { 0x0e200400, 0x9f200400, disas_simd_three_reg_same },
e7186d82 13676 { 0x0e008400, 0x9f208400, disas_simd_three_reg_same_extra },
384b26fb
AB
13677 { 0x0e200000, 0x9f200c00, disas_simd_three_reg_diff },
13678 { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
13679 { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
13680 { 0x0e000400, 0x9fe08400, disas_simd_copy },
9f82e0ff 13681 { 0x0f000000, 0x9f000400, disas_simd_indexed }, /* vector indexed */
384b26fb
AB
13682 /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */
13683 { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
13684 { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
13685 { 0x0e000000, 0xbf208c00, disas_simd_tb },
13686 { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
13687 { 0x2e000000, 0xbf208400, disas_simd_ext },
13688 { 0x5e200400, 0xdf200400, disas_simd_scalar_three_reg_same },
d9061ec3 13689 { 0x5e008400, 0xdf208400, disas_simd_scalar_three_reg_same_extra },
384b26fb
AB
13690 { 0x5e200000, 0xdf200c00, disas_simd_scalar_three_reg_diff },
13691 { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
13692 { 0x5e300800, 0xdf3e0c00, disas_simd_scalar_pairwise },
13693 { 0x5e000400, 0xdfe08400, disas_simd_scalar_copy },
9f82e0ff 13694 { 0x5f000000, 0xdf000400, disas_simd_indexed }, /* scalar indexed */
384b26fb
AB
13695 { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
13696 { 0x4e280800, 0xff3e0c00, disas_crypto_aes },
13697 { 0x5e000000, 0xff208c00, disas_crypto_three_reg_sha },
13698 { 0x5e280800, 0xff3e0c00, disas_crypto_two_reg_sha },
90b827d1
AB
13699 { 0xce608000, 0xffe0b000, disas_crypto_three_reg_sha512 },
13700 { 0xcec08000, 0xfffff000, disas_crypto_two_reg_sha512 },
cd270ade
AB
13701 { 0xce000000, 0xff808000, disas_crypto_four_reg },
13702 { 0xce800000, 0xffe00000, disas_crypto_xar },
80d6f4c6 13703 { 0xce408000, 0xffe0c000, disas_crypto_three_reg_imm2 },
376e8d6c 13704 { 0x0e400400, 0x9f60c400, disas_simd_three_reg_same_fp16 },
5d432be6 13705 { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 },
7c93b774 13706 { 0x5e400400, 0xdf60c400, disas_simd_scalar_three_reg_same_fp16 },
384b26fb
AB
13707 { 0x00000000, 0x00000000, NULL }
13708};
13709
faa0ba46
PM
13710static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
13711{
13712 /* Note that this is called with all non-FP cases from
13713 * table C3-6 so it must UNDEF for entries not specifically
13714 * allocated to instructions in that table.
13715 */
384b26fb
AB
13716 AArch64DecodeFn *fn = lookup_disas_fn(&data_proc_simd[0], insn);
13717 if (fn) {
13718 fn(s, insn);
13719 } else {
13720 unallocated_encoding(s);
13721 }
faa0ba46
PM
13722}
13723
ad7ee8a2
CF
13724/* C3.6 Data processing - SIMD and floating point */
13725static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
13726{
faa0ba46
PM
13727 if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
13728 disas_data_proc_fp(s, insn);
13729 } else {
13730 /* SIMD, including crypto */
13731 disas_data_proc_simd(s, insn);
13732 }
ad7ee8a2
CF
13733}
13734
13735/* C3.1 A64 instruction index by encoding */
40f860cd 13736static void disas_a64_insn(CPUARMState *env, DisasContext *s)
14ade10f
AG
13737{
13738 uint32_t insn;
13739
f9fd40eb 13740 insn = arm_ldl_code(env, s->pc, s->sctlr_b);
14ade10f
AG
13741 s->insn = insn;
13742 s->pc += 4;
13743
90e49638
PM
13744 s->fp_access_checked = false;
13745
ad7ee8a2 13746 switch (extract32(insn, 25, 4)) {
38388f7e 13747 case 0x0: case 0x1: case 0x3: /* UNALLOCATED */
14ade10f
AG
13748 unallocated_encoding(s);
13749 break;
38388f7e 13750 case 0x2:
cd208a1c 13751 if (!dc_isar_feature(aa64_sve, s) || !disas_sve(s, insn)) {
38388f7e
RH
13752 unallocated_encoding(s);
13753 }
13754 break;
ad7ee8a2
CF
13755 case 0x8: case 0x9: /* Data processing - immediate */
13756 disas_data_proc_imm(s, insn);
13757 break;
13758 case 0xa: case 0xb: /* Branch, exception generation and system insns */
13759 disas_b_exc_sys(s, insn);
13760 break;
13761 case 0x4:
13762 case 0x6:
13763 case 0xc:
13764 case 0xe: /* Loads and stores */
13765 disas_ldst(s, insn);
13766 break;
13767 case 0x5:
13768 case 0xd: /* Data processing - register */
13769 disas_data_proc_reg(s, insn);
13770 break;
13771 case 0x7:
13772 case 0xf: /* Data processing - SIMD and floating point */
13773 disas_data_proc_simd_fp(s, insn);
13774 break;
13775 default:
13776 assert(FALSE); /* all 15 cases should be handled above */
13777 break;
14ade10f 13778 }
11e169de
AG
13779
13780 /* if we allocated any temporaries, free them here */
13781 free_tmp_a64(s);
40f860cd 13782}
14ade10f 13783
b542683d
EC
13784static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
13785 CPUState *cpu)
40f860cd 13786{
dcba3a8d 13787 DisasContext *dc = container_of(dcbase, DisasContext, base);
5c039906
LV
13788 CPUARMState *env = cpu->env_ptr;
13789 ARMCPU *arm_cpu = arm_env_get_cpu(env);
aad821ac
RH
13790 uint32_t tb_flags = dc->base.tb->flags;
13791 int bound, core_mmu_idx;
40f860cd 13792
962fcbf2 13793 dc->isar = &arm_cpu->isar;
dcba3a8d 13794 dc->pc = dc->base.pc_first;
40f860cd
PM
13795 dc->condjmp = 0;
13796
13797 dc->aarch64 = 1;
cef9ee70
SS
13798 /* If we are coming from secure EL0 in a system with a 32-bit EL3, then
13799 * there is no secure EL1, so we route exceptions to EL3.
13800 */
13801 dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
13802 !arm_el_is_aa64(env, 3);
40f860cd 13803 dc->thumb = 0;
f9fd40eb 13804 dc->sctlr_b = 0;
aad821ac 13805 dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
40f860cd
PM
13806 dc->condexec_mask = 0;
13807 dc->condexec_cond = 0;
aad821ac
RH
13808 core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
13809 dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
476a4692 13810 dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII);
c1e37810 13811 dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
40f860cd 13812#if !defined(CONFIG_USER_ONLY)
c1e37810 13813 dc->user = (dc->current_el == 0);
40f860cd 13814#endif
aad821ac
RH
13815 dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
13816 dc->sve_excp_el = FIELD_EX32(tb_flags, TBFLAG_A64, SVEEXC_EL);
13817 dc->sve_len = (FIELD_EX32(tb_flags, TBFLAG_A64, ZCR_LEN) + 1) * 16;
0816ef1b 13818 dc->pauth_active = FIELD_EX32(tb_flags, TBFLAG_A64, PAUTH_ACTIVE);
40f860cd
PM
13819 dc->vec_len = 0;
13820 dc->vec_stride = 0;
5c039906 13821 dc->cp_regs = arm_cpu->cp_regs;
a984e42c 13822 dc->features = env->features;
40f860cd 13823
7ea47fe7
PM
13824 /* Single step state. The code-generation logic here is:
13825 * SS_ACTIVE == 0:
13826 * generate code with no special handling for single-stepping (except
13827 * that anything that can make us go to SS_ACTIVE == 1 must end the TB;
13828 * this happens anyway because those changes are all system register or
13829 * PSTATE writes).
13830 * SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
13831 * emit code for one insn
13832 * emit code to clear PSTATE.SS
13833 * emit code to generate software step exception for completed step
13834 * end TB (as usual for having generated an exception)
13835 * SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
13836 * emit code to generate a software step exception
13837 * end the TB
13838 */
aad821ac
RH
13839 dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE);
13840 dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS);
7ea47fe7 13841 dc->is_ldex = false;
dcbff19b 13842 dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
7ea47fe7 13843
dcc3a212
RH
13844 /* Bound the number of insns to execute to those left on the page. */
13845 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
13846
13847 /* If architectural single step active, limit to 1. */
13848 if (dc->ss_active) {
13849 bound = 1;
13850 }
b542683d 13851 dc->base.max_insns = MIN(dc->base.max_insns, bound);
24299c89 13852
11e169de 13853 init_tmp_a64_array(dc);
5c039906
LV
13854}
13855
23169224
LV
13856static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
13857{
23169224
LV
13858}
13859
a68956ad
LV
13860static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
13861{
13862 DisasContext *dc = container_of(dcbase, DisasContext, base);
13863
a68956ad 13864 tcg_gen_insn_start(dc->pc, 0, 0);
15fa08f8 13865 dc->insn_start = tcg_last_op();
a68956ad
LV
13866}
13867
0cb56b37
LV
13868static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
13869 const CPUBreakpoint *bp)
13870{
13871 DisasContext *dc = container_of(dcbase, DisasContext, base);
13872
13873 if (bp->flags & BP_CPU) {
13874 gen_a64_set_pc_im(dc->pc);
13875 gen_helper_check_breakpoints(cpu_env);
13876 /* End the TB early; it likely won't be executed */
13877 dc->base.is_jmp = DISAS_TOO_MANY;
13878 } else {
13879 gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
13880 /* The address covered by the breakpoint must be
13881 included in [tb->pc, tb->pc + tb->size) in order
13882 to for it to be properly cleared -- thus we
13883 increment the PC here so that the logic setting
13884 tb->size below does the right thing. */
13885 dc->pc += 4;
13886 dc->base.is_jmp = DISAS_NORETURN;
13887 }
13888
13889 return true;
13890}
13891
24299c89
LV
13892static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
13893{
13894 DisasContext *dc = container_of(dcbase, DisasContext, base);
13895 CPUARMState *env = cpu->env_ptr;
13896
13897 if (dc->ss_active && !dc->pstate_ss) {
13898 /* Singlestep state is Active-pending.
13899 * If we're in this state at the start of a TB then either
13900 * a) we just took an exception to an EL which is being debugged
13901 * and this is the first insn in the exception handler
13902 * b) debug exceptions were masked and we just unmasked them
13903 * without changing EL (eg by clearing PSTATE.D)
13904 * In either case we're going to take a swstep exception in the
13905 * "did not step an insn" case, and so the syndrome ISV and EX
13906 * bits should be zero.
13907 */
13908 assert(dc->base.num_insns == 1);
13909 gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
13910 default_exception_el(dc));
13911 dc->base.is_jmp = DISAS_NORETURN;
13912 } else {
13913 disas_a64_insn(env, dc);
13914 }
13915
24299c89 13916 dc->base.pc_next = dc->pc;
23169224 13917 translator_loop_temp_check(&dc->base);
24299c89
LV
13918}
13919
be407964
LV
13920static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
13921{
13922 DisasContext *dc = container_of(dcbase, DisasContext, base);
13923
13924 if (unlikely(dc->base.singlestep_enabled || dc->ss_active)) {
13925 /* Note that this means single stepping WFI doesn't halt the CPU.
13926 * For conditional branch insns this is harmless unreachable code as
13927 * gen_goto_tb() has already handled emitting the debug exception
13928 * (and thus a tb-jump is not possible when singlestepping).
13929 */
13930 switch (dc->base.is_jmp) {
13931 default:
13932 gen_a64_set_pc_im(dc->pc);
13933 /* fall through */
dddbba99 13934 case DISAS_EXIT:
be407964
LV
13935 case DISAS_JUMP:
13936 if (dc->base.singlestep_enabled) {
13937 gen_exception_internal(EXCP_DEBUG);
13938 } else {
13939 gen_step_complete_exception(dc);
13940 }
13941 break;
13942 case DISAS_NORETURN:
13943 break;
13944 }
13945 } else {
13946 switch (dc->base.is_jmp) {
13947 case DISAS_NEXT:
13948 case DISAS_TOO_MANY:
13949 gen_goto_tb(dc, 1, dc->pc);
13950 break;
13951 default:
13952 case DISAS_UPDATE:
13953 gen_a64_set_pc_im(dc->pc);
13954 /* fall through */
be407964 13955 case DISAS_EXIT:
07ea28b4 13956 tcg_gen_exit_tb(NULL, 0);
be407964 13957 break;
a75a52d6
VK
13958 case DISAS_JUMP:
13959 tcg_gen_lookup_and_goto_ptr();
13960 break;
be407964
LV
13961 case DISAS_NORETURN:
13962 case DISAS_SWI:
13963 break;
13964 case DISAS_WFE:
13965 gen_a64_set_pc_im(dc->pc);
13966 gen_helper_wfe(cpu_env);
13967 break;
13968 case DISAS_YIELD:
13969 gen_a64_set_pc_im(dc->pc);
13970 gen_helper_yield(cpu_env);
13971 break;
13972 case DISAS_WFI:
58803318 13973 {
be407964
LV
13974 /* This is a special case because we don't want to just halt the CPU
13975 * if trying to debug across a WFI.
13976 */
58803318
SS
13977 TCGv_i32 tmp = tcg_const_i32(4);
13978
be407964 13979 gen_a64_set_pc_im(dc->pc);
58803318
SS
13980 gen_helper_wfi(cpu_env, tmp);
13981 tcg_temp_free_i32(tmp);
be407964
LV
13982 /* The helper doesn't necessarily throw an exception, but we
13983 * must go back to the main loop to check for interrupts anyway.
13984 */
07ea28b4 13985 tcg_gen_exit_tb(NULL, 0);
be407964
LV
13986 break;
13987 }
58803318 13988 }
be407964 13989 }
23169224
LV
13990
13991 /* Functions above can change dc->pc, so re-align db->pc_next */
13992 dc->base.pc_next = dc->pc;
be407964
LV
13993}
13994
58350fa4
LV
13995static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
13996 CPUState *cpu)
13997{
13998 DisasContext *dc = container_of(dcbase, DisasContext, base);
13999
14000 qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
1d48474d 14001 log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
58350fa4
LV
14002}
14003
23169224
LV
14004const TranslatorOps aarch64_translator_ops = {
14005 .init_disas_context = aarch64_tr_init_disas_context,
14006 .tb_start = aarch64_tr_tb_start,
14007 .insn_start = aarch64_tr_insn_start,
14008 .breakpoint_check = aarch64_tr_breakpoint_check,
14009 .translate_insn = aarch64_tr_translate_insn,
14010 .tb_stop = aarch64_tr_tb_stop,
14011 .disas_log = aarch64_tr_disas_log,
14012};