xref: /qemu/target/arm/tcg/translate-neon.c (revision 8161b75357095fef54c76b1a6ed1e54d0e8655e0)
1625e3dd4SPeter Maydell /*
2625e3dd4SPeter Maydell  *  ARM translation: AArch32 Neon instructions
3625e3dd4SPeter Maydell  *
4625e3dd4SPeter Maydell  *  Copyright (c) 2003 Fabrice Bellard
5625e3dd4SPeter Maydell  *  Copyright (c) 2005-2007 CodeSourcery
6625e3dd4SPeter Maydell  *  Copyright (c) 2007 OpenedHand, Ltd.
7625e3dd4SPeter Maydell  *  Copyright (c) 2020 Linaro, Ltd.
8625e3dd4SPeter Maydell  *
9625e3dd4SPeter Maydell  * This library is free software; you can redistribute it and/or
10625e3dd4SPeter Maydell  * modify it under the terms of the GNU Lesser General Public
11625e3dd4SPeter Maydell  * License as published by the Free Software Foundation; either
12625e3dd4SPeter Maydell  * version 2 of the License, or (at your option) any later version.
13625e3dd4SPeter Maydell  *
14625e3dd4SPeter Maydell  * This library is distributed in the hope that it will be useful,
15625e3dd4SPeter Maydell  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16625e3dd4SPeter Maydell  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17625e3dd4SPeter Maydell  * Lesser General Public License for more details.
18625e3dd4SPeter Maydell  *
19625e3dd4SPeter Maydell  * You should have received a copy of the GNU Lesser General Public
20625e3dd4SPeter Maydell  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21625e3dd4SPeter Maydell  */
22625e3dd4SPeter Maydell 
23625e3dd4SPeter Maydell /*
24625e3dd4SPeter Maydell  * This file is intended to be included from translate.c; it uses
25625e3dd4SPeter Maydell  * some macros and definitions provided by that file.
26625e3dd4SPeter Maydell  * It might be possible to convert it to a standalone .c file eventually.
27625e3dd4SPeter Maydell  */
28625e3dd4SPeter Maydell 
29123ce4e3SPeter Maydell static inline int plus1(DisasContext *s, int x)
30123ce4e3SPeter Maydell {
31123ce4e3SPeter Maydell     return x + 1;
32123ce4e3SPeter Maydell }
33123ce4e3SPeter Maydell 
34625e3dd4SPeter Maydell /* Include the generated Neon decoder */
35625e3dd4SPeter Maydell #include "decode-neon-dp.inc.c"
36625e3dd4SPeter Maydell #include "decode-neon-ls.inc.c"
37625e3dd4SPeter Maydell #include "decode-neon-shared.inc.c"
38afff8de0SPeter Maydell 
39afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
40afff8de0SPeter Maydell {
41afff8de0SPeter Maydell     int opr_sz;
42afff8de0SPeter Maydell     TCGv_ptr fpst;
43afff8de0SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
44afff8de0SPeter Maydell 
45afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
46afff8de0SPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
47afff8de0SPeter Maydell         return false;
48afff8de0SPeter Maydell     }
49afff8de0SPeter Maydell 
50afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
51afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
52afff8de0SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
53afff8de0SPeter Maydell         return false;
54afff8de0SPeter Maydell     }
55afff8de0SPeter Maydell 
56afff8de0SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
57afff8de0SPeter Maydell         return false;
58afff8de0SPeter Maydell     }
59afff8de0SPeter Maydell 
60afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
61afff8de0SPeter Maydell         return true;
62afff8de0SPeter Maydell     }
63afff8de0SPeter Maydell 
64afff8de0SPeter Maydell     opr_sz = (1 + a->q) * 8;
65afff8de0SPeter Maydell     fpst = get_fpstatus_ptr(1);
66afff8de0SPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
67afff8de0SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
68afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vn),
69afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vm),
70afff8de0SPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
71afff8de0SPeter Maydell                        fn_gvec_ptr);
72afff8de0SPeter Maydell     tcg_temp_free_ptr(fpst);
73afff8de0SPeter Maydell     return true;
74afff8de0SPeter Maydell }
7594d5eb7bSPeter Maydell 
7694d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
7794d5eb7bSPeter Maydell {
7894d5eb7bSPeter Maydell     int opr_sz;
7994d5eb7bSPeter Maydell     TCGv_ptr fpst;
8094d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
8194d5eb7bSPeter Maydell 
8294d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
8394d5eb7bSPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
8494d5eb7bSPeter Maydell         return false;
8594d5eb7bSPeter Maydell     }
8694d5eb7bSPeter Maydell 
8794d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
8894d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
8994d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
9094d5eb7bSPeter Maydell         return false;
9194d5eb7bSPeter Maydell     }
9294d5eb7bSPeter Maydell 
9394d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
9494d5eb7bSPeter Maydell         return false;
9594d5eb7bSPeter Maydell     }
9694d5eb7bSPeter Maydell 
9794d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
9894d5eb7bSPeter Maydell         return true;
9994d5eb7bSPeter Maydell     }
10094d5eb7bSPeter Maydell 
10194d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
10294d5eb7bSPeter Maydell     fpst = get_fpstatus_ptr(1);
10394d5eb7bSPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
10494d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
10594d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
10694d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
10794d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
10894d5eb7bSPeter Maydell                        fn_gvec_ptr);
10994d5eb7bSPeter Maydell     tcg_temp_free_ptr(fpst);
11094d5eb7bSPeter Maydell     return true;
11194d5eb7bSPeter Maydell }
11232da0e33SPeter Maydell 
11332da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
11432da0e33SPeter Maydell {
11532da0e33SPeter Maydell     int opr_sz;
11632da0e33SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
11732da0e33SPeter Maydell 
11832da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
11932da0e33SPeter Maydell         return false;
12032da0e33SPeter Maydell     }
12132da0e33SPeter Maydell 
12232da0e33SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
12332da0e33SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
12432da0e33SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
12532da0e33SPeter Maydell         return false;
12632da0e33SPeter Maydell     }
12732da0e33SPeter Maydell 
12832da0e33SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
12932da0e33SPeter Maydell         return false;
13032da0e33SPeter Maydell     }
13132da0e33SPeter Maydell 
13232da0e33SPeter Maydell     if (!vfp_access_check(s)) {
13332da0e33SPeter Maydell         return true;
13432da0e33SPeter Maydell     }
13532da0e33SPeter Maydell 
13632da0e33SPeter Maydell     opr_sz = (1 + a->q) * 8;
13732da0e33SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
13832da0e33SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
13932da0e33SPeter Maydell                        vfp_reg_offset(1, a->vn),
14032da0e33SPeter Maydell                        vfp_reg_offset(1, a->vm),
14132da0e33SPeter Maydell                        opr_sz, opr_sz, 0, fn_gvec);
14232da0e33SPeter Maydell     return true;
14332da0e33SPeter Maydell }
1449a107e7bSPeter Maydell 
1459a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
1469a107e7bSPeter Maydell {
1479a107e7bSPeter Maydell     int opr_sz;
1489a107e7bSPeter Maydell 
1499a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
1509a107e7bSPeter Maydell         return false;
1519a107e7bSPeter Maydell     }
1529a107e7bSPeter Maydell 
1539a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1549a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1559a107e7bSPeter Maydell         (a->vd & 0x10)) {
1569a107e7bSPeter Maydell         return false;
1579a107e7bSPeter Maydell     }
1589a107e7bSPeter Maydell 
1599a107e7bSPeter Maydell     if (a->vd & a->q) {
1609a107e7bSPeter Maydell         return false;
1619a107e7bSPeter Maydell     }
1629a107e7bSPeter Maydell 
1639a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
1649a107e7bSPeter Maydell         return true;
1659a107e7bSPeter Maydell     }
1669a107e7bSPeter Maydell 
1679a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
1689a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
1699a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
1709a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
1719a107e7bSPeter Maydell                        cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
1729a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
1739a107e7bSPeter Maydell     return true;
1749a107e7bSPeter Maydell }
1757e1b5d61SPeter Maydell 
1767e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
1777e1b5d61SPeter Maydell {
1787e1b5d61SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
1797e1b5d61SPeter Maydell     int opr_sz;
1807e1b5d61SPeter Maydell     TCGv_ptr fpst;
1817e1b5d61SPeter Maydell 
1827e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
1837e1b5d61SPeter Maydell         return false;
1847e1b5d61SPeter Maydell     }
1857e1b5d61SPeter Maydell     if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) {
1867e1b5d61SPeter Maydell         return false;
1877e1b5d61SPeter Maydell     }
1887e1b5d61SPeter Maydell 
1897e1b5d61SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1907e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1917e1b5d61SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1927e1b5d61SPeter Maydell         return false;
1937e1b5d61SPeter Maydell     }
1947e1b5d61SPeter Maydell 
1957e1b5d61SPeter Maydell     if ((a->vd | a->vn) & a->q) {
1967e1b5d61SPeter Maydell         return false;
1977e1b5d61SPeter Maydell     }
1987e1b5d61SPeter Maydell 
1997e1b5d61SPeter Maydell     if (!vfp_access_check(s)) {
2007e1b5d61SPeter Maydell         return true;
2017e1b5d61SPeter Maydell     }
2027e1b5d61SPeter Maydell 
2037e1b5d61SPeter Maydell     fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx
2047e1b5d61SPeter Maydell                    : gen_helper_gvec_fcmlah_idx);
2057e1b5d61SPeter Maydell     opr_sz = (1 + a->q) * 8;
2067e1b5d61SPeter Maydell     fpst = get_fpstatus_ptr(1);
2077e1b5d61SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
2087e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vn),
2097e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vm),
2107e1b5d61SPeter Maydell                        fpst, opr_sz, opr_sz,
2117e1b5d61SPeter Maydell                        (a->index << 2) | a->rot, fn_gvec_ptr);
2127e1b5d61SPeter Maydell     tcg_temp_free_ptr(fpst);
2137e1b5d61SPeter Maydell     return true;
2147e1b5d61SPeter Maydell }
21535f5d4d1SPeter Maydell 
21635f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
21735f5d4d1SPeter Maydell {
21835f5d4d1SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
21935f5d4d1SPeter Maydell     int opr_sz;
22035f5d4d1SPeter Maydell     TCGv_ptr fpst;
22135f5d4d1SPeter Maydell 
22235f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
22335f5d4d1SPeter Maydell         return false;
22435f5d4d1SPeter Maydell     }
22535f5d4d1SPeter Maydell 
22635f5d4d1SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
22735f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
22835f5d4d1SPeter Maydell         ((a->vd | a->vn) & 0x10)) {
22935f5d4d1SPeter Maydell         return false;
23035f5d4d1SPeter Maydell     }
23135f5d4d1SPeter Maydell 
23235f5d4d1SPeter Maydell     if ((a->vd | a->vn) & a->q) {
23335f5d4d1SPeter Maydell         return false;
23435f5d4d1SPeter Maydell     }
23535f5d4d1SPeter Maydell 
23635f5d4d1SPeter Maydell     if (!vfp_access_check(s)) {
23735f5d4d1SPeter Maydell         return true;
23835f5d4d1SPeter Maydell     }
23935f5d4d1SPeter Maydell 
24035f5d4d1SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
24135f5d4d1SPeter Maydell     opr_sz = (1 + a->q) * 8;
24235f5d4d1SPeter Maydell     fpst = get_fpstatus_ptr(1);
24335f5d4d1SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
24435f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->vn),
24535f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->rm),
24635f5d4d1SPeter Maydell                        opr_sz, opr_sz, a->index, fn_gvec);
24735f5d4d1SPeter Maydell     tcg_temp_free_ptr(fpst);
24835f5d4d1SPeter Maydell     return true;
24935f5d4d1SPeter Maydell }
250d27e82f7SPeter Maydell 
251d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
252d27e82f7SPeter Maydell {
253d27e82f7SPeter Maydell     int opr_sz;
254d27e82f7SPeter Maydell 
255d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
256d27e82f7SPeter Maydell         return false;
257d27e82f7SPeter Maydell     }
258d27e82f7SPeter Maydell 
259d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
260d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
261d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
262d27e82f7SPeter Maydell         return false;
263d27e82f7SPeter Maydell     }
264d27e82f7SPeter Maydell 
265d27e82f7SPeter Maydell     if (a->vd & a->q) {
266d27e82f7SPeter Maydell         return false;
267d27e82f7SPeter Maydell     }
268d27e82f7SPeter Maydell 
269d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
270d27e82f7SPeter Maydell         return true;
271d27e82f7SPeter Maydell     }
272d27e82f7SPeter Maydell 
273d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
274d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
275d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
276d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
277d27e82f7SPeter Maydell                        cpu_env, opr_sz, opr_sz,
278d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
279d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
280d27e82f7SPeter Maydell     return true;
281d27e82f7SPeter Maydell }
282a27b4630SPeter Maydell 
283a27b4630SPeter Maydell static struct {
284a27b4630SPeter Maydell     int nregs;
285a27b4630SPeter Maydell     int interleave;
286a27b4630SPeter Maydell     int spacing;
287a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
288a27b4630SPeter Maydell     {1, 4, 1},
289a27b4630SPeter Maydell     {1, 4, 2},
290a27b4630SPeter Maydell     {4, 1, 1},
291a27b4630SPeter Maydell     {2, 2, 2},
292a27b4630SPeter Maydell     {1, 3, 1},
293a27b4630SPeter Maydell     {1, 3, 2},
294a27b4630SPeter Maydell     {3, 1, 1},
295a27b4630SPeter Maydell     {1, 1, 1},
296a27b4630SPeter Maydell     {1, 2, 1},
297a27b4630SPeter Maydell     {1, 2, 2},
298a27b4630SPeter Maydell     {2, 1, 1}
299a27b4630SPeter Maydell };
300a27b4630SPeter Maydell 
301a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
302a27b4630SPeter Maydell                                       int stride)
303a27b4630SPeter Maydell {
304a27b4630SPeter Maydell     if (rm != 15) {
305a27b4630SPeter Maydell         TCGv_i32 base;
306a27b4630SPeter Maydell 
307a27b4630SPeter Maydell         base = load_reg(s, rn);
308a27b4630SPeter Maydell         if (rm == 13) {
309a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
310a27b4630SPeter Maydell         } else {
311a27b4630SPeter Maydell             TCGv_i32 index;
312a27b4630SPeter Maydell             index = load_reg(s, rm);
313a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
314a27b4630SPeter Maydell             tcg_temp_free_i32(index);
315a27b4630SPeter Maydell         }
316a27b4630SPeter Maydell         store_reg(s, rn, base);
317a27b4630SPeter Maydell     }
318a27b4630SPeter Maydell }
319a27b4630SPeter Maydell 
320a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
321a27b4630SPeter Maydell {
322a27b4630SPeter Maydell     /* Neon load/store multiple structures */
323a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
324a27b4630SPeter Maydell     MemOp endian = s->be_data;
325a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
326a27b4630SPeter Maydell     int size = a->size;
327a27b4630SPeter Maydell     TCGv_i64 tmp64;
328a27b4630SPeter Maydell     TCGv_i32 addr, tmp;
329a27b4630SPeter Maydell 
330a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
331a27b4630SPeter Maydell         return false;
332a27b4630SPeter Maydell     }
333a27b4630SPeter Maydell 
334a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
335a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
336a27b4630SPeter Maydell         return false;
337a27b4630SPeter Maydell     }
338a27b4630SPeter Maydell     if (a->itype > 10) {
339a27b4630SPeter Maydell         return false;
340a27b4630SPeter Maydell     }
341a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
342a27b4630SPeter Maydell     switch (a->itype & 0xc) {
343a27b4630SPeter Maydell     case 4:
344a27b4630SPeter Maydell         if (a->align >= 2) {
345a27b4630SPeter Maydell             return false;
346a27b4630SPeter Maydell         }
347a27b4630SPeter Maydell         break;
348a27b4630SPeter Maydell     case 8:
349a27b4630SPeter Maydell         if (a->align == 3) {
350a27b4630SPeter Maydell             return false;
351a27b4630SPeter Maydell         }
352a27b4630SPeter Maydell         break;
353a27b4630SPeter Maydell     default:
354a27b4630SPeter Maydell         break;
355a27b4630SPeter Maydell     }
356a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
357a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
358a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
359a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
360a27b4630SPeter Maydell         return false;
361a27b4630SPeter Maydell     }
362a27b4630SPeter Maydell 
363a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
364a27b4630SPeter Maydell         return true;
365a27b4630SPeter Maydell     }
366a27b4630SPeter Maydell 
367a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
368a27b4630SPeter Maydell     if (size == 0) {
369a27b4630SPeter Maydell         endian = MO_LE;
370a27b4630SPeter Maydell     }
371a27b4630SPeter Maydell     /*
372a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
373a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
374a27b4630SPeter Maydell      */
375a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
376a27b4630SPeter Maydell         size = 3;
377a27b4630SPeter Maydell     }
378a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
379a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
380a27b4630SPeter Maydell     tmp = tcg_const_i32(1 << size);
381a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
382a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
383a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
384a27b4630SPeter Maydell             int xs;
385a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
386a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
387a27b4630SPeter Maydell 
388a27b4630SPeter Maydell                 if (a->l) {
389a27b4630SPeter Maydell                     gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
390a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
391a27b4630SPeter Maydell                 } else {
392a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
393a27b4630SPeter Maydell                     gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
394a27b4630SPeter Maydell                 }
395a27b4630SPeter Maydell                 tcg_gen_add_i32(addr, addr, tmp);
396a27b4630SPeter Maydell             }
397a27b4630SPeter Maydell         }
398a27b4630SPeter Maydell     }
399a27b4630SPeter Maydell     tcg_temp_free_i32(addr);
400a27b4630SPeter Maydell     tcg_temp_free_i32(tmp);
401a27b4630SPeter Maydell     tcg_temp_free_i64(tmp64);
402a27b4630SPeter Maydell 
403a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
404a27b4630SPeter Maydell     return true;
405a27b4630SPeter Maydell }
4063698747cSPeter Maydell 
4073698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
4083698747cSPeter Maydell {
4093698747cSPeter Maydell     /* Neon load single structure to all lanes */
4103698747cSPeter Maydell     int reg, stride, vec_size;
4113698747cSPeter Maydell     int vd = a->vd;
4123698747cSPeter Maydell     int size = a->size;
4133698747cSPeter Maydell     int nregs = a->n + 1;
4143698747cSPeter Maydell     TCGv_i32 addr, tmp;
4153698747cSPeter Maydell 
4163698747cSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
4173698747cSPeter Maydell         return false;
4183698747cSPeter Maydell     }
4193698747cSPeter Maydell 
4203698747cSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
4213698747cSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
4223698747cSPeter Maydell         return false;
4233698747cSPeter Maydell     }
4243698747cSPeter Maydell 
4253698747cSPeter Maydell     if (size == 3) {
4263698747cSPeter Maydell         if (nregs != 4 || a->a == 0) {
4273698747cSPeter Maydell             return false;
4283698747cSPeter Maydell         }
4293698747cSPeter Maydell         /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
4303698747cSPeter Maydell         size = 2;
4313698747cSPeter Maydell     }
4323698747cSPeter Maydell     if (nregs == 1 && a->a == 1 && size == 0) {
4333698747cSPeter Maydell         return false;
4343698747cSPeter Maydell     }
4353698747cSPeter Maydell     if (nregs == 3 && a->a == 1) {
4363698747cSPeter Maydell         return false;
4373698747cSPeter Maydell     }
4383698747cSPeter Maydell 
4393698747cSPeter Maydell     if (!vfp_access_check(s)) {
4403698747cSPeter Maydell         return true;
4413698747cSPeter Maydell     }
4423698747cSPeter Maydell 
4433698747cSPeter Maydell     /*
4443698747cSPeter Maydell      * VLD1 to all lanes: T bit indicates how many Dregs to write.
4453698747cSPeter Maydell      * VLD2/3/4 to all lanes: T bit indicates register stride.
4463698747cSPeter Maydell      */
4473698747cSPeter Maydell     stride = a->t ? 2 : 1;
4483698747cSPeter Maydell     vec_size = nregs == 1 ? stride * 8 : 8;
4493698747cSPeter Maydell 
4503698747cSPeter Maydell     tmp = tcg_temp_new_i32();
4513698747cSPeter Maydell     addr = tcg_temp_new_i32();
4523698747cSPeter Maydell     load_reg_var(s, addr, a->rn);
4533698747cSPeter Maydell     for (reg = 0; reg < nregs; reg++) {
4543698747cSPeter Maydell         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
4553698747cSPeter Maydell                         s->be_data | size);
4563698747cSPeter Maydell         if ((vd & 1) && vec_size == 16) {
4573698747cSPeter Maydell             /*
4583698747cSPeter Maydell              * We cannot write 16 bytes at once because the
4593698747cSPeter Maydell              * destination is unaligned.
4603698747cSPeter Maydell              */
4613698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
4623698747cSPeter Maydell                                  8, 8, tmp);
4633698747cSPeter Maydell             tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0),
4643698747cSPeter Maydell                              neon_reg_offset(vd, 0), 8, 8);
4653698747cSPeter Maydell         } else {
4663698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
4673698747cSPeter Maydell                                  vec_size, vec_size, tmp);
4683698747cSPeter Maydell         }
4693698747cSPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << size);
4703698747cSPeter Maydell         vd += stride;
4713698747cSPeter Maydell     }
4723698747cSPeter Maydell     tcg_temp_free_i32(tmp);
4733698747cSPeter Maydell     tcg_temp_free_i32(addr);
4743698747cSPeter Maydell 
4753698747cSPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
4763698747cSPeter Maydell 
4773698747cSPeter Maydell     return true;
4783698747cSPeter Maydell }
479123ce4e3SPeter Maydell 
480123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
481123ce4e3SPeter Maydell {
482123ce4e3SPeter Maydell     /* Neon load/store single structure to one lane */
483123ce4e3SPeter Maydell     int reg;
484123ce4e3SPeter Maydell     int nregs = a->n + 1;
485123ce4e3SPeter Maydell     int vd = a->vd;
486123ce4e3SPeter Maydell     TCGv_i32 addr, tmp;
487123ce4e3SPeter Maydell 
488123ce4e3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
489123ce4e3SPeter Maydell         return false;
490123ce4e3SPeter Maydell     }
491123ce4e3SPeter Maydell 
492123ce4e3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
493123ce4e3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
494123ce4e3SPeter Maydell         return false;
495123ce4e3SPeter Maydell     }
496123ce4e3SPeter Maydell 
497123ce4e3SPeter Maydell     /* Catch the UNDEF cases. This is unavoidably a bit messy. */
498123ce4e3SPeter Maydell     switch (nregs) {
499123ce4e3SPeter Maydell     case 1:
500123ce4e3SPeter Maydell         if (((a->align & (1 << a->size)) != 0) ||
501123ce4e3SPeter Maydell             (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) {
502123ce4e3SPeter Maydell             return false;
503123ce4e3SPeter Maydell         }
504123ce4e3SPeter Maydell         break;
505123ce4e3SPeter Maydell     case 3:
506123ce4e3SPeter Maydell         if ((a->align & 1) != 0) {
507123ce4e3SPeter Maydell             return false;
508123ce4e3SPeter Maydell         }
509123ce4e3SPeter Maydell         /* fall through */
510123ce4e3SPeter Maydell     case 2:
511123ce4e3SPeter Maydell         if (a->size == 2 && (a->align & 2) != 0) {
512123ce4e3SPeter Maydell             return false;
513123ce4e3SPeter Maydell         }
514123ce4e3SPeter Maydell         break;
515123ce4e3SPeter Maydell     case 4:
516123ce4e3SPeter Maydell         if ((a->size == 2) && ((a->align & 3) == 3)) {
517123ce4e3SPeter Maydell             return false;
518123ce4e3SPeter Maydell         }
519123ce4e3SPeter Maydell         break;
520123ce4e3SPeter Maydell     default:
521123ce4e3SPeter Maydell         abort();
522123ce4e3SPeter Maydell     }
523123ce4e3SPeter Maydell     if ((vd + a->stride * (nregs - 1)) > 31) {
524123ce4e3SPeter Maydell         /*
525123ce4e3SPeter Maydell          * Attempts to write off the end of the register file are
526123ce4e3SPeter Maydell          * UNPREDICTABLE; we choose to UNDEF because otherwise we would
527123ce4e3SPeter Maydell          * access off the end of the array that holds the register data.
528123ce4e3SPeter Maydell          */
529123ce4e3SPeter Maydell         return false;
530123ce4e3SPeter Maydell     }
531123ce4e3SPeter Maydell 
532123ce4e3SPeter Maydell     if (!vfp_access_check(s)) {
533123ce4e3SPeter Maydell         return true;
534123ce4e3SPeter Maydell     }
535123ce4e3SPeter Maydell 
536123ce4e3SPeter Maydell     tmp = tcg_temp_new_i32();
537123ce4e3SPeter Maydell     addr = tcg_temp_new_i32();
538123ce4e3SPeter Maydell     load_reg_var(s, addr, a->rn);
539123ce4e3SPeter Maydell     /*
540123ce4e3SPeter Maydell      * TODO: if we implemented alignment exceptions, we should check
541123ce4e3SPeter Maydell      * addr against the alignment encoded in a->align here.
542123ce4e3SPeter Maydell      */
543123ce4e3SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
544123ce4e3SPeter Maydell         if (a->l) {
545123ce4e3SPeter Maydell             gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
546123ce4e3SPeter Maydell                             s->be_data | a->size);
547123ce4e3SPeter Maydell             neon_store_element(vd, a->reg_idx, a->size, tmp);
548123ce4e3SPeter Maydell         } else { /* Store */
549123ce4e3SPeter Maydell             neon_load_element(tmp, vd, a->reg_idx, a->size);
550123ce4e3SPeter Maydell             gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
551123ce4e3SPeter Maydell                             s->be_data | a->size);
552123ce4e3SPeter Maydell         }
553123ce4e3SPeter Maydell         vd += a->stride;
554123ce4e3SPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << a->size);
555123ce4e3SPeter Maydell     }
556123ce4e3SPeter Maydell     tcg_temp_free_i32(addr);
557123ce4e3SPeter Maydell     tcg_temp_free_i32(tmp);
558123ce4e3SPeter Maydell 
559123ce4e3SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
560123ce4e3SPeter Maydell 
561123ce4e3SPeter Maydell     return true;
562123ce4e3SPeter Maydell }
563a4e143acSPeter Maydell 
564a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
565a4e143acSPeter Maydell {
566a4e143acSPeter Maydell     int vec_size = a->q ? 16 : 8;
567a4e143acSPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
568a4e143acSPeter Maydell     int rn_ofs = neon_reg_offset(a->vn, 0);
569a4e143acSPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
570a4e143acSPeter Maydell 
571a4e143acSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
572a4e143acSPeter Maydell         return false;
573a4e143acSPeter Maydell     }
574a4e143acSPeter Maydell 
575a4e143acSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
576a4e143acSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
577a4e143acSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
578a4e143acSPeter Maydell         return false;
579a4e143acSPeter Maydell     }
580a4e143acSPeter Maydell 
581a4e143acSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
582a4e143acSPeter Maydell         return false;
583a4e143acSPeter Maydell     }
584a4e143acSPeter Maydell 
585a4e143acSPeter Maydell     if (!vfp_access_check(s)) {
586a4e143acSPeter Maydell         return true;
587a4e143acSPeter Maydell     }
588a4e143acSPeter Maydell 
589a4e143acSPeter Maydell     fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
590a4e143acSPeter Maydell     return true;
591a4e143acSPeter Maydell }
592a4e143acSPeter Maydell 
593a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC)                                            \
594a4e143acSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
595a4e143acSPeter Maydell     {                                                                   \
596a4e143acSPeter Maydell         return do_3same(s, a, FUNC);                                    \
597a4e143acSPeter Maydell     }
598a4e143acSPeter Maydell 
599a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add)
600a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub)
60135a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and)
60235a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc)
60335a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or)
60435a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc)
60535a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor)
6068161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl)
6078161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl)
60835a548edSPeter Maydell 
60935a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */
61035a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3)                               \
61135a548edSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
61235a548edSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
61335a548edSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
61435a548edSPeter Maydell     {                                                                   \
61535a548edSPeter Maydell         tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz);    \
61635a548edSPeter Maydell     }                                                                   \
61735a548edSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
61835a548edSPeter Maydell 
61935a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
62035a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
62135a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
62236b59310SPeter Maydell 
62336b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC)                                    \
62436b59310SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
62536b59310SPeter Maydell     {                                                                   \
62636b59310SPeter Maydell         if (a->size == 3) {                                             \
62736b59310SPeter Maydell             return false;                                               \
62836b59310SPeter Maydell         }                                                               \
62936b59310SPeter Maydell         return do_3same(s, a, FUNC);                                    \
63036b59310SPeter Maydell     }
63136b59310SPeter Maydell 
63236b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
63336b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
63436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
63536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
6360de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
63727106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla)
63827106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls)
6398161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst)
64002bd0cdbSPeter Maydell 
64102bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND)                                        \
64202bd0cdbSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
64302bd0cdbSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
64402bd0cdbSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
64502bd0cdbSPeter Maydell     {                                                                   \
64602bd0cdbSPeter Maydell         tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
64702bd0cdbSPeter Maydell     }                                                                   \
64802bd0cdbSPeter Maydell     DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
64902bd0cdbSPeter Maydell 
65002bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
65102bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
65202bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
65302bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
65402bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
65502bd0cdbSPeter Maydell 
6567a9497f1SPeter Maydell #define DO_3SAME_GVEC4(INSN, OPARRAY)                                   \
6577a9497f1SPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
6587a9497f1SPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
6597a9497f1SPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
6607a9497f1SPeter Maydell     {                                                                   \
6617a9497f1SPeter Maydell         tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),           \
6627a9497f1SPeter Maydell                        rn_ofs, rm_ofs, oprsz, maxsz, &OPARRAY[vece]);   \
6637a9497f1SPeter Maydell     }                                                                   \
6647a9497f1SPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
6657a9497f1SPeter Maydell 
6667a9497f1SPeter Maydell DO_3SAME_GVEC4(VQADD_S, sqadd_op)
6677a9497f1SPeter Maydell DO_3SAME_GVEC4(VQADD_U, uqadd_op)
6687a9497f1SPeter Maydell DO_3SAME_GVEC4(VQSUB_S, sqsub_op)
6697a9497f1SPeter Maydell DO_3SAME_GVEC4(VQSUB_U, uqsub_op)
6700de34fd4SPeter Maydell 
6710de34fd4SPeter Maydell static void gen_VMUL_p_3s(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
6720de34fd4SPeter Maydell                            uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)
6730de34fd4SPeter Maydell {
6740de34fd4SPeter Maydell     tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz,
6750de34fd4SPeter Maydell                        0, gen_helper_gvec_pmul_b);
6760de34fd4SPeter Maydell }
6770de34fd4SPeter Maydell 
6780de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
6790de34fd4SPeter Maydell {
6800de34fd4SPeter Maydell     if (a->size != 0) {
6810de34fd4SPeter Maydell         return false;
6820de34fd4SPeter Maydell     }
6830de34fd4SPeter Maydell     return do_3same(s, a, gen_VMUL_p_3s);
6840de34fd4SPeter Maydell }
685