xref: /qemu/target/arm/tcg/translate-neon.c (revision 5de3fd045be11b74cd0fbf36c6d4fb8387d5463b)
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 
3466432d6bSPeter Maydell static inline int rsub_64(DisasContext *s, int x)
3566432d6bSPeter Maydell {
3666432d6bSPeter Maydell     return 64 - x;
3766432d6bSPeter Maydell }
3866432d6bSPeter Maydell 
3966432d6bSPeter Maydell static inline int rsub_32(DisasContext *s, int x)
4066432d6bSPeter Maydell {
4166432d6bSPeter Maydell     return 32 - x;
4266432d6bSPeter Maydell }
4366432d6bSPeter Maydell static inline int rsub_16(DisasContext *s, int x)
4466432d6bSPeter Maydell {
4566432d6bSPeter Maydell     return 16 - x;
4666432d6bSPeter Maydell }
4766432d6bSPeter Maydell static inline int rsub_8(DisasContext *s, int x)
4866432d6bSPeter Maydell {
4966432d6bSPeter Maydell     return 8 - x;
5066432d6bSPeter Maydell }
5166432d6bSPeter Maydell 
52625e3dd4SPeter Maydell /* Include the generated Neon decoder */
53625e3dd4SPeter Maydell #include "decode-neon-dp.inc.c"
54625e3dd4SPeter Maydell #include "decode-neon-ls.inc.c"
55625e3dd4SPeter Maydell #include "decode-neon-shared.inc.c"
56afff8de0SPeter Maydell 
57afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
58afff8de0SPeter Maydell {
59afff8de0SPeter Maydell     int opr_sz;
60afff8de0SPeter Maydell     TCGv_ptr fpst;
61afff8de0SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
62afff8de0SPeter Maydell 
63afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
64afff8de0SPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
65afff8de0SPeter Maydell         return false;
66afff8de0SPeter Maydell     }
67afff8de0SPeter Maydell 
68afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
69afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
70afff8de0SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
71afff8de0SPeter Maydell         return false;
72afff8de0SPeter Maydell     }
73afff8de0SPeter Maydell 
74afff8de0SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
75afff8de0SPeter Maydell         return false;
76afff8de0SPeter Maydell     }
77afff8de0SPeter Maydell 
78afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
79afff8de0SPeter Maydell         return true;
80afff8de0SPeter Maydell     }
81afff8de0SPeter Maydell 
82afff8de0SPeter Maydell     opr_sz = (1 + a->q) * 8;
83afff8de0SPeter Maydell     fpst = get_fpstatus_ptr(1);
84afff8de0SPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
85afff8de0SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
86afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vn),
87afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vm),
88afff8de0SPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
89afff8de0SPeter Maydell                        fn_gvec_ptr);
90afff8de0SPeter Maydell     tcg_temp_free_ptr(fpst);
91afff8de0SPeter Maydell     return true;
92afff8de0SPeter Maydell }
9394d5eb7bSPeter Maydell 
9494d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
9594d5eb7bSPeter Maydell {
9694d5eb7bSPeter Maydell     int opr_sz;
9794d5eb7bSPeter Maydell     TCGv_ptr fpst;
9894d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
9994d5eb7bSPeter Maydell 
10094d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
10194d5eb7bSPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
10294d5eb7bSPeter Maydell         return false;
10394d5eb7bSPeter Maydell     }
10494d5eb7bSPeter Maydell 
10594d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
10694d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
10794d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
10894d5eb7bSPeter Maydell         return false;
10994d5eb7bSPeter Maydell     }
11094d5eb7bSPeter Maydell 
11194d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
11294d5eb7bSPeter Maydell         return false;
11394d5eb7bSPeter Maydell     }
11494d5eb7bSPeter Maydell 
11594d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
11694d5eb7bSPeter Maydell         return true;
11794d5eb7bSPeter Maydell     }
11894d5eb7bSPeter Maydell 
11994d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
12094d5eb7bSPeter Maydell     fpst = get_fpstatus_ptr(1);
12194d5eb7bSPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
12294d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
12394d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
12494d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
12594d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
12694d5eb7bSPeter Maydell                        fn_gvec_ptr);
12794d5eb7bSPeter Maydell     tcg_temp_free_ptr(fpst);
12894d5eb7bSPeter Maydell     return true;
12994d5eb7bSPeter Maydell }
13032da0e33SPeter Maydell 
13132da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
13232da0e33SPeter Maydell {
13332da0e33SPeter Maydell     int opr_sz;
13432da0e33SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
13532da0e33SPeter Maydell 
13632da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
13732da0e33SPeter Maydell         return false;
13832da0e33SPeter Maydell     }
13932da0e33SPeter Maydell 
14032da0e33SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
14132da0e33SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
14232da0e33SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
14332da0e33SPeter Maydell         return false;
14432da0e33SPeter Maydell     }
14532da0e33SPeter Maydell 
14632da0e33SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
14732da0e33SPeter Maydell         return false;
14832da0e33SPeter Maydell     }
14932da0e33SPeter Maydell 
15032da0e33SPeter Maydell     if (!vfp_access_check(s)) {
15132da0e33SPeter Maydell         return true;
15232da0e33SPeter Maydell     }
15332da0e33SPeter Maydell 
15432da0e33SPeter Maydell     opr_sz = (1 + a->q) * 8;
15532da0e33SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
15632da0e33SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
15732da0e33SPeter Maydell                        vfp_reg_offset(1, a->vn),
15832da0e33SPeter Maydell                        vfp_reg_offset(1, a->vm),
15932da0e33SPeter Maydell                        opr_sz, opr_sz, 0, fn_gvec);
16032da0e33SPeter Maydell     return true;
16132da0e33SPeter Maydell }
1629a107e7bSPeter Maydell 
1639a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
1649a107e7bSPeter Maydell {
1659a107e7bSPeter Maydell     int opr_sz;
1669a107e7bSPeter Maydell 
1679a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
1689a107e7bSPeter Maydell         return false;
1699a107e7bSPeter Maydell     }
1709a107e7bSPeter Maydell 
1719a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1729a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1739a107e7bSPeter Maydell         (a->vd & 0x10)) {
1749a107e7bSPeter Maydell         return false;
1759a107e7bSPeter Maydell     }
1769a107e7bSPeter Maydell 
1779a107e7bSPeter Maydell     if (a->vd & a->q) {
1789a107e7bSPeter Maydell         return false;
1799a107e7bSPeter Maydell     }
1809a107e7bSPeter Maydell 
1819a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
1829a107e7bSPeter Maydell         return true;
1839a107e7bSPeter Maydell     }
1849a107e7bSPeter Maydell 
1859a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
1869a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
1879a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
1889a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
1899a107e7bSPeter Maydell                        cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
1909a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
1919a107e7bSPeter Maydell     return true;
1929a107e7bSPeter Maydell }
1937e1b5d61SPeter Maydell 
1947e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
1957e1b5d61SPeter Maydell {
1967e1b5d61SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
1977e1b5d61SPeter Maydell     int opr_sz;
1987e1b5d61SPeter Maydell     TCGv_ptr fpst;
1997e1b5d61SPeter Maydell 
2007e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
2017e1b5d61SPeter Maydell         return false;
2027e1b5d61SPeter Maydell     }
2037e1b5d61SPeter Maydell     if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) {
2047e1b5d61SPeter Maydell         return false;
2057e1b5d61SPeter Maydell     }
2067e1b5d61SPeter Maydell 
2077e1b5d61SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2087e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2097e1b5d61SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2107e1b5d61SPeter Maydell         return false;
2117e1b5d61SPeter Maydell     }
2127e1b5d61SPeter Maydell 
2137e1b5d61SPeter Maydell     if ((a->vd | a->vn) & a->q) {
2147e1b5d61SPeter Maydell         return false;
2157e1b5d61SPeter Maydell     }
2167e1b5d61SPeter Maydell 
2177e1b5d61SPeter Maydell     if (!vfp_access_check(s)) {
2187e1b5d61SPeter Maydell         return true;
2197e1b5d61SPeter Maydell     }
2207e1b5d61SPeter Maydell 
2217e1b5d61SPeter Maydell     fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx
2227e1b5d61SPeter Maydell                    : gen_helper_gvec_fcmlah_idx);
2237e1b5d61SPeter Maydell     opr_sz = (1 + a->q) * 8;
2247e1b5d61SPeter Maydell     fpst = get_fpstatus_ptr(1);
2257e1b5d61SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
2267e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vn),
2277e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vm),
2287e1b5d61SPeter Maydell                        fpst, opr_sz, opr_sz,
2297e1b5d61SPeter Maydell                        (a->index << 2) | a->rot, fn_gvec_ptr);
2307e1b5d61SPeter Maydell     tcg_temp_free_ptr(fpst);
2317e1b5d61SPeter Maydell     return true;
2327e1b5d61SPeter Maydell }
23335f5d4d1SPeter Maydell 
23435f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
23535f5d4d1SPeter Maydell {
23635f5d4d1SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
23735f5d4d1SPeter Maydell     int opr_sz;
23835f5d4d1SPeter Maydell     TCGv_ptr fpst;
23935f5d4d1SPeter Maydell 
24035f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
24135f5d4d1SPeter Maydell         return false;
24235f5d4d1SPeter Maydell     }
24335f5d4d1SPeter Maydell 
24435f5d4d1SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
24535f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
24635f5d4d1SPeter Maydell         ((a->vd | a->vn) & 0x10)) {
24735f5d4d1SPeter Maydell         return false;
24835f5d4d1SPeter Maydell     }
24935f5d4d1SPeter Maydell 
25035f5d4d1SPeter Maydell     if ((a->vd | a->vn) & a->q) {
25135f5d4d1SPeter Maydell         return false;
25235f5d4d1SPeter Maydell     }
25335f5d4d1SPeter Maydell 
25435f5d4d1SPeter Maydell     if (!vfp_access_check(s)) {
25535f5d4d1SPeter Maydell         return true;
25635f5d4d1SPeter Maydell     }
25735f5d4d1SPeter Maydell 
25835f5d4d1SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
25935f5d4d1SPeter Maydell     opr_sz = (1 + a->q) * 8;
26035f5d4d1SPeter Maydell     fpst = get_fpstatus_ptr(1);
26135f5d4d1SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
26235f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->vn),
26335f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->rm),
26435f5d4d1SPeter Maydell                        opr_sz, opr_sz, a->index, fn_gvec);
26535f5d4d1SPeter Maydell     tcg_temp_free_ptr(fpst);
26635f5d4d1SPeter Maydell     return true;
26735f5d4d1SPeter Maydell }
268d27e82f7SPeter Maydell 
269d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
270d27e82f7SPeter Maydell {
271d27e82f7SPeter Maydell     int opr_sz;
272d27e82f7SPeter Maydell 
273d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
274d27e82f7SPeter Maydell         return false;
275d27e82f7SPeter Maydell     }
276d27e82f7SPeter Maydell 
277d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
278d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
279d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
280d27e82f7SPeter Maydell         return false;
281d27e82f7SPeter Maydell     }
282d27e82f7SPeter Maydell 
283d27e82f7SPeter Maydell     if (a->vd & a->q) {
284d27e82f7SPeter Maydell         return false;
285d27e82f7SPeter Maydell     }
286d27e82f7SPeter Maydell 
287d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
288d27e82f7SPeter Maydell         return true;
289d27e82f7SPeter Maydell     }
290d27e82f7SPeter Maydell 
291d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
292d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
293d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
294d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
295d27e82f7SPeter Maydell                        cpu_env, opr_sz, opr_sz,
296d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
297d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
298d27e82f7SPeter Maydell     return true;
299d27e82f7SPeter Maydell }
300a27b4630SPeter Maydell 
301a27b4630SPeter Maydell static struct {
302a27b4630SPeter Maydell     int nregs;
303a27b4630SPeter Maydell     int interleave;
304a27b4630SPeter Maydell     int spacing;
305a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
306a27b4630SPeter Maydell     {1, 4, 1},
307a27b4630SPeter Maydell     {1, 4, 2},
308a27b4630SPeter Maydell     {4, 1, 1},
309a27b4630SPeter Maydell     {2, 2, 2},
310a27b4630SPeter Maydell     {1, 3, 1},
311a27b4630SPeter Maydell     {1, 3, 2},
312a27b4630SPeter Maydell     {3, 1, 1},
313a27b4630SPeter Maydell     {1, 1, 1},
314a27b4630SPeter Maydell     {1, 2, 1},
315a27b4630SPeter Maydell     {1, 2, 2},
316a27b4630SPeter Maydell     {2, 1, 1}
317a27b4630SPeter Maydell };
318a27b4630SPeter Maydell 
319a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
320a27b4630SPeter Maydell                                       int stride)
321a27b4630SPeter Maydell {
322a27b4630SPeter Maydell     if (rm != 15) {
323a27b4630SPeter Maydell         TCGv_i32 base;
324a27b4630SPeter Maydell 
325a27b4630SPeter Maydell         base = load_reg(s, rn);
326a27b4630SPeter Maydell         if (rm == 13) {
327a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
328a27b4630SPeter Maydell         } else {
329a27b4630SPeter Maydell             TCGv_i32 index;
330a27b4630SPeter Maydell             index = load_reg(s, rm);
331a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
332a27b4630SPeter Maydell             tcg_temp_free_i32(index);
333a27b4630SPeter Maydell         }
334a27b4630SPeter Maydell         store_reg(s, rn, base);
335a27b4630SPeter Maydell     }
336a27b4630SPeter Maydell }
337a27b4630SPeter Maydell 
338a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
339a27b4630SPeter Maydell {
340a27b4630SPeter Maydell     /* Neon load/store multiple structures */
341a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
342a27b4630SPeter Maydell     MemOp endian = s->be_data;
343a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
344a27b4630SPeter Maydell     int size = a->size;
345a27b4630SPeter Maydell     TCGv_i64 tmp64;
346a27b4630SPeter Maydell     TCGv_i32 addr, tmp;
347a27b4630SPeter Maydell 
348a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
349a27b4630SPeter Maydell         return false;
350a27b4630SPeter Maydell     }
351a27b4630SPeter Maydell 
352a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
353a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
354a27b4630SPeter Maydell         return false;
355a27b4630SPeter Maydell     }
356a27b4630SPeter Maydell     if (a->itype > 10) {
357a27b4630SPeter Maydell         return false;
358a27b4630SPeter Maydell     }
359a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
360a27b4630SPeter Maydell     switch (a->itype & 0xc) {
361a27b4630SPeter Maydell     case 4:
362a27b4630SPeter Maydell         if (a->align >= 2) {
363a27b4630SPeter Maydell             return false;
364a27b4630SPeter Maydell         }
365a27b4630SPeter Maydell         break;
366a27b4630SPeter Maydell     case 8:
367a27b4630SPeter Maydell         if (a->align == 3) {
368a27b4630SPeter Maydell             return false;
369a27b4630SPeter Maydell         }
370a27b4630SPeter Maydell         break;
371a27b4630SPeter Maydell     default:
372a27b4630SPeter Maydell         break;
373a27b4630SPeter Maydell     }
374a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
375a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
376a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
377a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
378a27b4630SPeter Maydell         return false;
379a27b4630SPeter Maydell     }
380a27b4630SPeter Maydell 
381a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
382a27b4630SPeter Maydell         return true;
383a27b4630SPeter Maydell     }
384a27b4630SPeter Maydell 
385a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
386a27b4630SPeter Maydell     if (size == 0) {
387a27b4630SPeter Maydell         endian = MO_LE;
388a27b4630SPeter Maydell     }
389a27b4630SPeter Maydell     /*
390a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
391a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
392a27b4630SPeter Maydell      */
393a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
394a27b4630SPeter Maydell         size = 3;
395a27b4630SPeter Maydell     }
396a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
397a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
398a27b4630SPeter Maydell     tmp = tcg_const_i32(1 << size);
399a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
400a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
401a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
402a27b4630SPeter Maydell             int xs;
403a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
404a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
405a27b4630SPeter Maydell 
406a27b4630SPeter Maydell                 if (a->l) {
407a27b4630SPeter Maydell                     gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
408a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
409a27b4630SPeter Maydell                 } else {
410a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
411a27b4630SPeter Maydell                     gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
412a27b4630SPeter Maydell                 }
413a27b4630SPeter Maydell                 tcg_gen_add_i32(addr, addr, tmp);
414a27b4630SPeter Maydell             }
415a27b4630SPeter Maydell         }
416a27b4630SPeter Maydell     }
417a27b4630SPeter Maydell     tcg_temp_free_i32(addr);
418a27b4630SPeter Maydell     tcg_temp_free_i32(tmp);
419a27b4630SPeter Maydell     tcg_temp_free_i64(tmp64);
420a27b4630SPeter Maydell 
421a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
422a27b4630SPeter Maydell     return true;
423a27b4630SPeter Maydell }
4243698747cSPeter Maydell 
4253698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
4263698747cSPeter Maydell {
4273698747cSPeter Maydell     /* Neon load single structure to all lanes */
4283698747cSPeter Maydell     int reg, stride, vec_size;
4293698747cSPeter Maydell     int vd = a->vd;
4303698747cSPeter Maydell     int size = a->size;
4313698747cSPeter Maydell     int nregs = a->n + 1;
4323698747cSPeter Maydell     TCGv_i32 addr, tmp;
4333698747cSPeter Maydell 
4343698747cSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
4353698747cSPeter Maydell         return false;
4363698747cSPeter Maydell     }
4373698747cSPeter Maydell 
4383698747cSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
4393698747cSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
4403698747cSPeter Maydell         return false;
4413698747cSPeter Maydell     }
4423698747cSPeter Maydell 
4433698747cSPeter Maydell     if (size == 3) {
4443698747cSPeter Maydell         if (nregs != 4 || a->a == 0) {
4453698747cSPeter Maydell             return false;
4463698747cSPeter Maydell         }
4473698747cSPeter Maydell         /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
4483698747cSPeter Maydell         size = 2;
4493698747cSPeter Maydell     }
4503698747cSPeter Maydell     if (nregs == 1 && a->a == 1 && size == 0) {
4513698747cSPeter Maydell         return false;
4523698747cSPeter Maydell     }
4533698747cSPeter Maydell     if (nregs == 3 && a->a == 1) {
4543698747cSPeter Maydell         return false;
4553698747cSPeter Maydell     }
4563698747cSPeter Maydell 
4573698747cSPeter Maydell     if (!vfp_access_check(s)) {
4583698747cSPeter Maydell         return true;
4593698747cSPeter Maydell     }
4603698747cSPeter Maydell 
4613698747cSPeter Maydell     /*
4623698747cSPeter Maydell      * VLD1 to all lanes: T bit indicates how many Dregs to write.
4633698747cSPeter Maydell      * VLD2/3/4 to all lanes: T bit indicates register stride.
4643698747cSPeter Maydell      */
4653698747cSPeter Maydell     stride = a->t ? 2 : 1;
4663698747cSPeter Maydell     vec_size = nregs == 1 ? stride * 8 : 8;
4673698747cSPeter Maydell 
4683698747cSPeter Maydell     tmp = tcg_temp_new_i32();
4693698747cSPeter Maydell     addr = tcg_temp_new_i32();
4703698747cSPeter Maydell     load_reg_var(s, addr, a->rn);
4713698747cSPeter Maydell     for (reg = 0; reg < nregs; reg++) {
4723698747cSPeter Maydell         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
4733698747cSPeter Maydell                         s->be_data | size);
4743698747cSPeter Maydell         if ((vd & 1) && vec_size == 16) {
4753698747cSPeter Maydell             /*
4763698747cSPeter Maydell              * We cannot write 16 bytes at once because the
4773698747cSPeter Maydell              * destination is unaligned.
4783698747cSPeter Maydell              */
4793698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
4803698747cSPeter Maydell                                  8, 8, tmp);
4813698747cSPeter Maydell             tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0),
4823698747cSPeter Maydell                              neon_reg_offset(vd, 0), 8, 8);
4833698747cSPeter Maydell         } else {
4843698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
4853698747cSPeter Maydell                                  vec_size, vec_size, tmp);
4863698747cSPeter Maydell         }
4873698747cSPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << size);
4883698747cSPeter Maydell         vd += stride;
4893698747cSPeter Maydell     }
4903698747cSPeter Maydell     tcg_temp_free_i32(tmp);
4913698747cSPeter Maydell     tcg_temp_free_i32(addr);
4923698747cSPeter Maydell 
4933698747cSPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
4943698747cSPeter Maydell 
4953698747cSPeter Maydell     return true;
4963698747cSPeter Maydell }
497123ce4e3SPeter Maydell 
498123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
499123ce4e3SPeter Maydell {
500123ce4e3SPeter Maydell     /* Neon load/store single structure to one lane */
501123ce4e3SPeter Maydell     int reg;
502123ce4e3SPeter Maydell     int nregs = a->n + 1;
503123ce4e3SPeter Maydell     int vd = a->vd;
504123ce4e3SPeter Maydell     TCGv_i32 addr, tmp;
505123ce4e3SPeter Maydell 
506123ce4e3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
507123ce4e3SPeter Maydell         return false;
508123ce4e3SPeter Maydell     }
509123ce4e3SPeter Maydell 
510123ce4e3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
511123ce4e3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
512123ce4e3SPeter Maydell         return false;
513123ce4e3SPeter Maydell     }
514123ce4e3SPeter Maydell 
515123ce4e3SPeter Maydell     /* Catch the UNDEF cases. This is unavoidably a bit messy. */
516123ce4e3SPeter Maydell     switch (nregs) {
517123ce4e3SPeter Maydell     case 1:
518123ce4e3SPeter Maydell         if (((a->align & (1 << a->size)) != 0) ||
519123ce4e3SPeter Maydell             (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) {
520123ce4e3SPeter Maydell             return false;
521123ce4e3SPeter Maydell         }
522123ce4e3SPeter Maydell         break;
523123ce4e3SPeter Maydell     case 3:
524123ce4e3SPeter Maydell         if ((a->align & 1) != 0) {
525123ce4e3SPeter Maydell             return false;
526123ce4e3SPeter Maydell         }
527123ce4e3SPeter Maydell         /* fall through */
528123ce4e3SPeter Maydell     case 2:
529123ce4e3SPeter Maydell         if (a->size == 2 && (a->align & 2) != 0) {
530123ce4e3SPeter Maydell             return false;
531123ce4e3SPeter Maydell         }
532123ce4e3SPeter Maydell         break;
533123ce4e3SPeter Maydell     case 4:
534123ce4e3SPeter Maydell         if ((a->size == 2) && ((a->align & 3) == 3)) {
535123ce4e3SPeter Maydell             return false;
536123ce4e3SPeter Maydell         }
537123ce4e3SPeter Maydell         break;
538123ce4e3SPeter Maydell     default:
539123ce4e3SPeter Maydell         abort();
540123ce4e3SPeter Maydell     }
541123ce4e3SPeter Maydell     if ((vd + a->stride * (nregs - 1)) > 31) {
542123ce4e3SPeter Maydell         /*
543123ce4e3SPeter Maydell          * Attempts to write off the end of the register file are
544123ce4e3SPeter Maydell          * UNPREDICTABLE; we choose to UNDEF because otherwise we would
545123ce4e3SPeter Maydell          * access off the end of the array that holds the register data.
546123ce4e3SPeter Maydell          */
547123ce4e3SPeter Maydell         return false;
548123ce4e3SPeter Maydell     }
549123ce4e3SPeter Maydell 
550123ce4e3SPeter Maydell     if (!vfp_access_check(s)) {
551123ce4e3SPeter Maydell         return true;
552123ce4e3SPeter Maydell     }
553123ce4e3SPeter Maydell 
554123ce4e3SPeter Maydell     tmp = tcg_temp_new_i32();
555123ce4e3SPeter Maydell     addr = tcg_temp_new_i32();
556123ce4e3SPeter Maydell     load_reg_var(s, addr, a->rn);
557123ce4e3SPeter Maydell     /*
558123ce4e3SPeter Maydell      * TODO: if we implemented alignment exceptions, we should check
559123ce4e3SPeter Maydell      * addr against the alignment encoded in a->align here.
560123ce4e3SPeter Maydell      */
561123ce4e3SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
562123ce4e3SPeter Maydell         if (a->l) {
563123ce4e3SPeter Maydell             gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
564123ce4e3SPeter Maydell                             s->be_data | a->size);
565123ce4e3SPeter Maydell             neon_store_element(vd, a->reg_idx, a->size, tmp);
566123ce4e3SPeter Maydell         } else { /* Store */
567123ce4e3SPeter Maydell             neon_load_element(tmp, vd, a->reg_idx, a->size);
568123ce4e3SPeter Maydell             gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
569123ce4e3SPeter Maydell                             s->be_data | a->size);
570123ce4e3SPeter Maydell         }
571123ce4e3SPeter Maydell         vd += a->stride;
572123ce4e3SPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << a->size);
573123ce4e3SPeter Maydell     }
574123ce4e3SPeter Maydell     tcg_temp_free_i32(addr);
575123ce4e3SPeter Maydell     tcg_temp_free_i32(tmp);
576123ce4e3SPeter Maydell 
577123ce4e3SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
578123ce4e3SPeter Maydell 
579123ce4e3SPeter Maydell     return true;
580123ce4e3SPeter Maydell }
581a4e143acSPeter Maydell 
582a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
583a4e143acSPeter Maydell {
584a4e143acSPeter Maydell     int vec_size = a->q ? 16 : 8;
585a4e143acSPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
586a4e143acSPeter Maydell     int rn_ofs = neon_reg_offset(a->vn, 0);
587a4e143acSPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
588a4e143acSPeter Maydell 
589a4e143acSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
590a4e143acSPeter Maydell         return false;
591a4e143acSPeter Maydell     }
592a4e143acSPeter Maydell 
593a4e143acSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
594a4e143acSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
595a4e143acSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
596a4e143acSPeter Maydell         return false;
597a4e143acSPeter Maydell     }
598a4e143acSPeter Maydell 
599a4e143acSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
600a4e143acSPeter Maydell         return false;
601a4e143acSPeter Maydell     }
602a4e143acSPeter Maydell 
603a4e143acSPeter Maydell     if (!vfp_access_check(s)) {
604a4e143acSPeter Maydell         return true;
605a4e143acSPeter Maydell     }
606a4e143acSPeter Maydell 
607a4e143acSPeter Maydell     fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
608a4e143acSPeter Maydell     return true;
609a4e143acSPeter Maydell }
610a4e143acSPeter Maydell 
611a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC)                                            \
612a4e143acSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
613a4e143acSPeter Maydell     {                                                                   \
614a4e143acSPeter Maydell         return do_3same(s, a, FUNC);                                    \
615a4e143acSPeter Maydell     }
616a4e143acSPeter Maydell 
617a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add)
618a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub)
61935a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and)
62035a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc)
62135a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or)
62235a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc)
62335a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor)
6248161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl)
6258161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl)
626c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc)
627c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc)
628c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc)
629c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc)
63035a548edSPeter Maydell 
63135a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */
63235a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3)                               \
63335a548edSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
63435a548edSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
63535a548edSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
63635a548edSPeter Maydell     {                                                                   \
63735a548edSPeter Maydell         tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz);    \
63835a548edSPeter Maydell     }                                                                   \
63935a548edSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
64035a548edSPeter Maydell 
64135a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
64235a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
64335a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
64436b59310SPeter Maydell 
64536b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC)                                    \
64636b59310SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
64736b59310SPeter Maydell     {                                                                   \
64836b59310SPeter Maydell         if (a->size == 3) {                                             \
64936b59310SPeter Maydell             return false;                                               \
65036b59310SPeter Maydell         }                                                               \
65136b59310SPeter Maydell         return do_3same(s, a, FUNC);                                    \
65236b59310SPeter Maydell     }
65336b59310SPeter Maydell 
65436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
65536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
65636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
65736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
6580de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
65927106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla)
66027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls)
6618161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst)
6627715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd)
6637715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba)
6647715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd)
6657715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba)
66602bd0cdbSPeter Maydell 
66702bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND)                                        \
66802bd0cdbSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
66902bd0cdbSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
67002bd0cdbSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
67102bd0cdbSPeter Maydell     {                                                                   \
67202bd0cdbSPeter Maydell         tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
67302bd0cdbSPeter Maydell     }                                                                   \
67402bd0cdbSPeter Maydell     DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
67502bd0cdbSPeter Maydell 
67602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
67702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
67802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
67902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
68002bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
68102bd0cdbSPeter Maydell 
682effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC)                                        \
683effa992fSRichard Henderson     static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,  \
684effa992fSRichard Henderson                          uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)  \
685effa992fSRichard Henderson     {                                                                      \
686effa992fSRichard Henderson         tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \
6870de34fd4SPeter Maydell     }
6880de34fd4SPeter Maydell 
689effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b)
690effa992fSRichard Henderson 
6910de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
6920de34fd4SPeter Maydell {
6930de34fd4SPeter Maydell     if (a->size != 0) {
6940de34fd4SPeter Maydell         return false;
6950de34fd4SPeter Maydell     }
6960de34fd4SPeter Maydell     return do_3same(s, a, gen_VMUL_p_3s);
6970de34fd4SPeter Maydell }
698a0635695SPeter Maydell 
699a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC)                                         \
700a0635695SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
701a0635695SPeter Maydell     {                                                                   \
702a0635695SPeter Maydell         if (!dc_isar_feature(aa32_rdm, s)) {                            \
703a0635695SPeter Maydell             return false;                                               \
704a0635695SPeter Maydell         }                                                               \
705a0635695SPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
706a0635695SPeter Maydell             return false;                                               \
707a0635695SPeter Maydell         }                                                               \
708a0635695SPeter Maydell         return do_3same(s, a, FUNC);                                    \
709a0635695SPeter Maydell     }
710a0635695SPeter Maydell 
711a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc)
712a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc)
71321290edfSPeter Maydell 
714afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC)                                             \
715afc8b7d3SRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
716afc8b7d3SRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
717afc8b7d3SRichard Henderson     {                                                                   \
718afc8b7d3SRichard Henderson         if (!dc_isar_feature(aa32_sha1, s)) {                           \
719afc8b7d3SRichard Henderson             return false;                                               \
720afc8b7d3SRichard Henderson         }                                                               \
721afc8b7d3SRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
72221290edfSPeter Maydell     }
72321290edfSPeter Maydell 
724afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c)
725afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p)
726afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m)
727afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0)
72821290edfSPeter Maydell 
729effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC)                                             \
730effa992fSRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
731effa992fSRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
732effa992fSRichard Henderson     {                                                                   \
733effa992fSRichard Henderson         if (!dc_isar_feature(aa32_sha2, s)) {                           \
734effa992fSRichard Henderson             return false;                                               \
735effa992fSRichard Henderson         }                                                               \
736effa992fSRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
73721290edfSPeter Maydell     }
73821290edfSPeter Maydell 
739effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h)
740effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2)
741effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1)
74235d4352fSPeter Maydell 
74335d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC)                                         \
74435d4352fSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
74535d4352fSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
74635d4352fSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
74735d4352fSPeter Maydell     {                                                                   \
74835d4352fSPeter Maydell         static const GVecGen3 op = { .fni8 = FUNC };                    \
74935d4352fSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op);      \
75035d4352fSPeter Maydell     }                                                                   \
75135d4352fSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
75235d4352fSPeter Maydell 
75335d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC)                                     \
75435d4352fSPeter Maydell     static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)    \
75535d4352fSPeter Maydell     {                                                                   \
75635d4352fSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
75735d4352fSPeter Maydell     }                                                                   \
75835d4352fSPeter Maydell     DO_3SAME_64(INSN, gen_##INSN##_elt)
75935d4352fSPeter Maydell 
76035d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64)
76135d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64)
76235d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64)
76335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64)
76435d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64)
76535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64)
766cb294bcaSPeter Maydell 
767cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC)                                         \
768cb294bcaSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
769cb294bcaSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
770cb294bcaSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
771cb294bcaSPeter Maydell     {                                                                   \
772cb294bcaSPeter Maydell         static const GVecGen3 ops[4] = {                                \
773cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##8 },                      \
774cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##16 },                     \
775cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##32 },                     \
776cb294bcaSPeter Maydell             { 0 },                                                      \
777cb294bcaSPeter Maydell         };                                                              \
778cb294bcaSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
779cb294bcaSPeter Maydell     }                                                                   \
780cb294bcaSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
781cb294bcaSPeter Maydell     {                                                                   \
782cb294bcaSPeter Maydell         if (a->size > 2) {                                              \
783cb294bcaSPeter Maydell             return false;                                               \
784cb294bcaSPeter Maydell         }                                                               \
785cb294bcaSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
786cb294bcaSPeter Maydell     }
787cb294bcaSPeter Maydell 
7886812dfdcSPeter Maydell /*
7896812dfdcSPeter Maydell  * Some helper functions need to be passed the cpu_env. In order
7906812dfdcSPeter Maydell  * to use those with the gvec APIs like tcg_gen_gvec_3() we need
7916812dfdcSPeter Maydell  * to create wrapper functions whose prototype is a NeonGenTwoOpFn()
7926812dfdcSPeter Maydell  * and which call a NeonGenTwoOpEnvFn().
7936812dfdcSPeter Maydell  */
7946812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC)                                     \
7956812dfdcSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m)            \
7966812dfdcSPeter Maydell     {                                                                   \
7976812dfdcSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
7986812dfdcSPeter Maydell     }
7996812dfdcSPeter Maydell 
8006812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC)                                     \
8016812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8);        \
8026812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16);      \
8036812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32);      \
8046812dfdcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
8056812dfdcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
8066812dfdcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
8076812dfdcSPeter Maydell     {                                                                   \
8086812dfdcSPeter Maydell         static const GVecGen3 ops[4] = {                                \
8096812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp8 },                            \
8106812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
8116812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
8126812dfdcSPeter Maydell             { 0 },                                                      \
8136812dfdcSPeter Maydell         };                                                              \
8146812dfdcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
8156812dfdcSPeter Maydell     }                                                                   \
8166812dfdcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
8176812dfdcSPeter Maydell     {                                                                   \
8186812dfdcSPeter Maydell         if (a->size > 2) {                                              \
8196812dfdcSPeter Maydell             return false;                                               \
8206812dfdcSPeter Maydell         }                                                               \
8216812dfdcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
8226812dfdcSPeter Maydell     }
8236812dfdcSPeter Maydell 
824cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s)
825cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u)
8268e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s)
8278e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u)
8288e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s)
8298e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u)
8306812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s)
8316812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u)
8326812dfdcSPeter Maydell 
8336812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s)
8346812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u)
8356812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s)
8366812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u)
837059c2398SPeter Maydell 
838059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn)
839059c2398SPeter Maydell {
840059c2398SPeter Maydell     /* Operations handled pairwise 32 bits at a time */
841059c2398SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3;
842059c2398SPeter Maydell 
843059c2398SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
844059c2398SPeter Maydell         return false;
845059c2398SPeter Maydell     }
846059c2398SPeter Maydell 
847059c2398SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
848059c2398SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
849059c2398SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
850059c2398SPeter Maydell         return false;
851059c2398SPeter Maydell     }
852059c2398SPeter Maydell 
853059c2398SPeter Maydell     if (a->size == 3) {
854059c2398SPeter Maydell         return false;
855059c2398SPeter Maydell     }
856059c2398SPeter Maydell 
857059c2398SPeter Maydell     if (!vfp_access_check(s)) {
858059c2398SPeter Maydell         return true;
859059c2398SPeter Maydell     }
860059c2398SPeter Maydell 
861059c2398SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
862059c2398SPeter Maydell 
863059c2398SPeter Maydell     /*
864059c2398SPeter Maydell      * Note that we have to be careful not to clobber the source operands
865059c2398SPeter Maydell      * in the "vm == vd" case by storing the result of the first pass too
866059c2398SPeter Maydell      * early. Since Q is 0 there are always just two passes, so instead
867059c2398SPeter Maydell      * of a complicated loop over each pass we just unroll.
868059c2398SPeter Maydell      */
869059c2398SPeter Maydell     tmp = neon_load_reg(a->vn, 0);
870059c2398SPeter Maydell     tmp2 = neon_load_reg(a->vn, 1);
871059c2398SPeter Maydell     fn(tmp, tmp, tmp2);
872059c2398SPeter Maydell     tcg_temp_free_i32(tmp2);
873059c2398SPeter Maydell 
874059c2398SPeter Maydell     tmp3 = neon_load_reg(a->vm, 0);
875059c2398SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
876059c2398SPeter Maydell     fn(tmp3, tmp3, tmp2);
877059c2398SPeter Maydell     tcg_temp_free_i32(tmp2);
878059c2398SPeter Maydell 
879059c2398SPeter Maydell     neon_store_reg(a->vd, 0, tmp);
880059c2398SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
881059c2398SPeter Maydell     return true;
882059c2398SPeter Maydell }
883059c2398SPeter Maydell 
884059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func)                                       \
885059c2398SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
886059c2398SPeter Maydell     {                                                                   \
887059c2398SPeter Maydell         static NeonGenTwoOpFn * const fns[] = {                         \
888059c2398SPeter Maydell             gen_helper_neon_##func##8,                                  \
889059c2398SPeter Maydell             gen_helper_neon_##func##16,                                 \
890059c2398SPeter Maydell             gen_helper_neon_##func##32,                                 \
891059c2398SPeter Maydell         };                                                              \
892059c2398SPeter Maydell         if (a->size > 2) {                                              \
893059c2398SPeter Maydell             return false;                                               \
894059c2398SPeter Maydell         }                                                               \
895059c2398SPeter Maydell         return do_3same_pair(s, a, fns[a->size]);                       \
896059c2398SPeter Maydell     }
897059c2398SPeter Maydell 
898059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions.  */
899059c2398SPeter Maydell #define gen_helper_neon_pmax_s32  tcg_gen_smax_i32
900059c2398SPeter Maydell #define gen_helper_neon_pmax_u32  tcg_gen_umax_i32
901059c2398SPeter Maydell #define gen_helper_neon_pmin_s32  tcg_gen_smin_i32
902059c2398SPeter Maydell #define gen_helper_neon_pmin_u32  tcg_gen_umin_i32
903fa22827dSPeter Maydell #define gen_helper_neon_padd_u32  tcg_gen_add_i32
904059c2398SPeter Maydell 
905059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s)
906059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s)
907059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u)
908059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u)
909fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u)
9107ecc28bcSPeter Maydell 
9117ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC)                                    \
9127ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16);    \
9137ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32);    \
9147ecc28bcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
9157ecc28bcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
9167ecc28bcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
9177ecc28bcSPeter Maydell     {                                                                   \
9187ecc28bcSPeter Maydell         static const GVecGen3 ops[2] = {                                \
9197ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
9207ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
9217ecc28bcSPeter Maydell         };                                                              \
9227ecc28bcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \
9237ecc28bcSPeter Maydell     }                                                                   \
9247ecc28bcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
9257ecc28bcSPeter Maydell     {                                                                   \
9267ecc28bcSPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
9277ecc28bcSPeter Maydell             return false;                                               \
9287ecc28bcSPeter Maydell         }                                                               \
9297ecc28bcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
9307ecc28bcSPeter Maydell     }
9317ecc28bcSPeter Maydell 
9327ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh)
9337ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh)
934a26a352bSPeter Maydell 
9358aa71eadSPeter Maydell static bool do_3same_fp(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn,
9368aa71eadSPeter Maydell                         bool reads_vd)
9378aa71eadSPeter Maydell {
9388aa71eadSPeter Maydell     /*
9398aa71eadSPeter Maydell      * FP operations handled elementwise 32 bits at a time.
9408aa71eadSPeter Maydell      * If reads_vd is true then the old value of Vd will be
9418aa71eadSPeter Maydell      * loaded before calling the callback function. This is
9428aa71eadSPeter Maydell      * used for multiply-accumulate type operations.
9438aa71eadSPeter Maydell      */
9448aa71eadSPeter Maydell     TCGv_i32 tmp, tmp2;
9458aa71eadSPeter Maydell     int pass;
9468aa71eadSPeter Maydell 
9478aa71eadSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
9488aa71eadSPeter Maydell         return false;
9498aa71eadSPeter Maydell     }
9508aa71eadSPeter Maydell 
9518aa71eadSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
9528aa71eadSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
9538aa71eadSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
9548aa71eadSPeter Maydell         return false;
9558aa71eadSPeter Maydell     }
9568aa71eadSPeter Maydell 
9578aa71eadSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
9588aa71eadSPeter Maydell         return false;
9598aa71eadSPeter Maydell     }
9608aa71eadSPeter Maydell 
9618aa71eadSPeter Maydell     if (!vfp_access_check(s)) {
9628aa71eadSPeter Maydell         return true;
9638aa71eadSPeter Maydell     }
9648aa71eadSPeter Maydell 
9658aa71eadSPeter Maydell     TCGv_ptr fpstatus = get_fpstatus_ptr(1);
9668aa71eadSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
9678aa71eadSPeter Maydell         tmp = neon_load_reg(a->vn, pass);
9688aa71eadSPeter Maydell         tmp2 = neon_load_reg(a->vm, pass);
9698aa71eadSPeter Maydell         if (reads_vd) {
9708aa71eadSPeter Maydell             TCGv_i32 tmp_rd = neon_load_reg(a->vd, pass);
9718aa71eadSPeter Maydell             fn(tmp_rd, tmp, tmp2, fpstatus);
9728aa71eadSPeter Maydell             neon_store_reg(a->vd, pass, tmp_rd);
9738aa71eadSPeter Maydell             tcg_temp_free_i32(tmp);
9748aa71eadSPeter Maydell         } else {
9758aa71eadSPeter Maydell             fn(tmp, tmp, tmp2, fpstatus);
9768aa71eadSPeter Maydell             neon_store_reg(a->vd, pass, tmp);
9778aa71eadSPeter Maydell         }
9788aa71eadSPeter Maydell         tcg_temp_free_i32(tmp2);
9798aa71eadSPeter Maydell     }
9808aa71eadSPeter Maydell     tcg_temp_free_ptr(fpstatus);
9818aa71eadSPeter Maydell     return true;
9828aa71eadSPeter Maydell }
9838aa71eadSPeter Maydell 
984a26a352bSPeter Maydell /*
985a26a352bSPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
986a26a352bSPeter Maydell  * which is an architecture extension we don't implement yet.
987a26a352bSPeter Maydell  */
988a26a352bSPeter Maydell #define DO_3S_FP_GVEC(INSN,FUNC)                                        \
989a26a352bSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
990a26a352bSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
991a26a352bSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
992a26a352bSPeter Maydell     {                                                                   \
993a26a352bSPeter Maydell         TCGv_ptr fpst = get_fpstatus_ptr(1);                            \
994a26a352bSPeter Maydell         tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst,                \
995a26a352bSPeter Maydell                            oprsz, maxsz, 0, FUNC);                      \
996a26a352bSPeter Maydell         tcg_temp_free_ptr(fpst);                                        \
997a26a352bSPeter Maydell     }                                                                   \
998a26a352bSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a)     \
999a26a352bSPeter Maydell     {                                                                   \
1000a26a352bSPeter Maydell         if (a->size != 0) {                                             \
1001a26a352bSPeter Maydell             /* TODO fp16 support */                                     \
1002a26a352bSPeter Maydell             return false;                                               \
1003a26a352bSPeter Maydell         }                                                               \
1004a26a352bSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
1005a26a352bSPeter Maydell     }
1006a26a352bSPeter Maydell 
1007a26a352bSPeter Maydell 
1008a26a352bSPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s)
1009a26a352bSPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s)
1010a26a352bSPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s)
10118aa71eadSPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s)
10128aa71eadSPeter Maydell 
10138aa71eadSPeter Maydell /*
10148aa71eadSPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
10158aa71eadSPeter Maydell  * which is an architecture extension we don't implement yet.
10168aa71eadSPeter Maydell  */
10178aa71eadSPeter Maydell #define DO_3S_FP(INSN,FUNC,READS_VD)                                \
10188aa71eadSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \
10198aa71eadSPeter Maydell     {                                                               \
10208aa71eadSPeter Maydell         if (a->size != 0) {                                         \
10218aa71eadSPeter Maydell             /* TODO fp16 support */                                 \
10228aa71eadSPeter Maydell             return false;                                           \
10238aa71eadSPeter Maydell         }                                                           \
10248aa71eadSPeter Maydell         return do_3same_fp(s, a, FUNC, READS_VD);                   \
10258aa71eadSPeter Maydell     }
10268aa71eadSPeter Maydell 
1027727ff1d6SPeter Maydell DO_3S_FP(VCEQ, gen_helper_neon_ceq_f32, false)
1028727ff1d6SPeter Maydell DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false)
1029727ff1d6SPeter Maydell DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false)
1030727ff1d6SPeter Maydell DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false)
1031727ff1d6SPeter Maydell DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false)
1032d5fdf9e9SPeter Maydell DO_3S_FP(VMAX, gen_helper_vfp_maxs, false)
1033d5fdf9e9SPeter Maydell DO_3S_FP(VMIN, gen_helper_vfp_mins, false)
1034727ff1d6SPeter Maydell 
10358aa71eadSPeter Maydell static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
10368aa71eadSPeter Maydell                             TCGv_ptr fpstatus)
10378aa71eadSPeter Maydell {
10388aa71eadSPeter Maydell     gen_helper_vfp_muls(vn, vn, vm, fpstatus);
10398aa71eadSPeter Maydell     gen_helper_vfp_adds(vd, vd, vn, fpstatus);
10408aa71eadSPeter Maydell }
10418aa71eadSPeter Maydell 
10428aa71eadSPeter Maydell static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
10438aa71eadSPeter Maydell                             TCGv_ptr fpstatus)
10448aa71eadSPeter Maydell {
10458aa71eadSPeter Maydell     gen_helper_vfp_muls(vn, vn, vm, fpstatus);
10468aa71eadSPeter Maydell     gen_helper_vfp_subs(vd, vd, vn, fpstatus);
10478aa71eadSPeter Maydell }
10488aa71eadSPeter Maydell 
10498aa71eadSPeter Maydell DO_3S_FP(VMLA, gen_VMLA_fp_3s, true)
10508aa71eadSPeter Maydell DO_3S_FP(VMLS, gen_VMLS_fp_3s, true)
1051ab978335SPeter Maydell 
1052d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a)
1053d5fdf9e9SPeter Maydell {
1054d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1055d5fdf9e9SPeter Maydell         return false;
1056d5fdf9e9SPeter Maydell     }
1057d5fdf9e9SPeter Maydell 
1058d5fdf9e9SPeter Maydell     if (a->size != 0) {
1059d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1060d5fdf9e9SPeter Maydell         return false;
1061d5fdf9e9SPeter Maydell     }
1062d5fdf9e9SPeter Maydell 
1063d5fdf9e9SPeter Maydell     return do_3same_fp(s, a, gen_helper_vfp_maxnums, false);
1064d5fdf9e9SPeter Maydell }
1065d5fdf9e9SPeter Maydell 
1066d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a)
1067d5fdf9e9SPeter Maydell {
1068d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1069d5fdf9e9SPeter Maydell         return false;
1070d5fdf9e9SPeter Maydell     }
1071d5fdf9e9SPeter Maydell 
1072d5fdf9e9SPeter Maydell     if (a->size != 0) {
1073d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1074d5fdf9e9SPeter Maydell         return false;
1075d5fdf9e9SPeter Maydell     }
1076d5fdf9e9SPeter Maydell 
1077d5fdf9e9SPeter Maydell     return do_3same_fp(s, a, gen_helper_vfp_minnums, false);
1078d5fdf9e9SPeter Maydell }
1079d5fdf9e9SPeter Maydell 
1080d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRECPS_tramp, gen_helper_recps_f32)
1081d5fdf9e9SPeter Maydell 
1082d5fdf9e9SPeter Maydell static void gen_VRECPS_fp_3s(unsigned vece, uint32_t rd_ofs,
1083d5fdf9e9SPeter Maydell                              uint32_t rn_ofs, uint32_t rm_ofs,
1084d5fdf9e9SPeter Maydell                              uint32_t oprsz, uint32_t maxsz)
1085d5fdf9e9SPeter Maydell {
1086d5fdf9e9SPeter Maydell     static const GVecGen3 ops = { .fni4 = gen_VRECPS_tramp };
1087d5fdf9e9SPeter Maydell     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops);
1088d5fdf9e9SPeter Maydell }
1089d5fdf9e9SPeter Maydell 
1090d5fdf9e9SPeter Maydell static bool trans_VRECPS_fp_3s(DisasContext *s, arg_3same *a)
1091d5fdf9e9SPeter Maydell {
1092d5fdf9e9SPeter Maydell     if (a->size != 0) {
1093d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1094d5fdf9e9SPeter Maydell         return false;
1095d5fdf9e9SPeter Maydell     }
1096d5fdf9e9SPeter Maydell 
1097d5fdf9e9SPeter Maydell     return do_3same(s, a, gen_VRECPS_fp_3s);
1098d5fdf9e9SPeter Maydell }
1099d5fdf9e9SPeter Maydell 
1100d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRSQRTS_tramp, gen_helper_rsqrts_f32)
1101d5fdf9e9SPeter Maydell 
1102d5fdf9e9SPeter Maydell static void gen_VRSQRTS_fp_3s(unsigned vece, uint32_t rd_ofs,
1103d5fdf9e9SPeter Maydell                               uint32_t rn_ofs, uint32_t rm_ofs,
1104d5fdf9e9SPeter Maydell                               uint32_t oprsz, uint32_t maxsz)
1105d5fdf9e9SPeter Maydell {
1106d5fdf9e9SPeter Maydell     static const GVecGen3 ops = { .fni4 = gen_VRSQRTS_tramp };
1107d5fdf9e9SPeter Maydell     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops);
1108d5fdf9e9SPeter Maydell }
1109d5fdf9e9SPeter Maydell 
1110d5fdf9e9SPeter Maydell static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a)
1111d5fdf9e9SPeter Maydell {
1112d5fdf9e9SPeter Maydell     if (a->size != 0) {
1113d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1114d5fdf9e9SPeter Maydell         return false;
1115d5fdf9e9SPeter Maydell     }
1116d5fdf9e9SPeter Maydell 
1117d5fdf9e9SPeter Maydell     return do_3same(s, a, gen_VRSQRTS_fp_3s);
1118d5fdf9e9SPeter Maydell }
1119d5fdf9e9SPeter Maydell 
1120e95485f8SPeter Maydell static void gen_VFMA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
1121e95485f8SPeter Maydell                             TCGv_ptr fpstatus)
1122e95485f8SPeter Maydell {
1123e95485f8SPeter Maydell     gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus);
1124e95485f8SPeter Maydell }
1125e95485f8SPeter Maydell 
1126e95485f8SPeter Maydell static bool trans_VFMA_fp_3s(DisasContext *s, arg_3same *a)
1127e95485f8SPeter Maydell {
1128e95485f8SPeter Maydell     if (!dc_isar_feature(aa32_simdfmac, s)) {
1129e95485f8SPeter Maydell         return false;
1130e95485f8SPeter Maydell     }
1131e95485f8SPeter Maydell 
1132e95485f8SPeter Maydell     if (a->size != 0) {
1133e95485f8SPeter Maydell         /* TODO fp16 support */
1134e95485f8SPeter Maydell         return false;
1135e95485f8SPeter Maydell     }
1136e95485f8SPeter Maydell 
1137e95485f8SPeter Maydell     return do_3same_fp(s, a, gen_VFMA_fp_3s, true);
1138e95485f8SPeter Maydell }
1139e95485f8SPeter Maydell 
1140e95485f8SPeter Maydell static void gen_VFMS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
1141e95485f8SPeter Maydell                             TCGv_ptr fpstatus)
1142e95485f8SPeter Maydell {
1143e95485f8SPeter Maydell     gen_helper_vfp_negs(vn, vn);
1144e95485f8SPeter Maydell     gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus);
1145e95485f8SPeter Maydell }
1146e95485f8SPeter Maydell 
1147e95485f8SPeter Maydell static bool trans_VFMS_fp_3s(DisasContext *s, arg_3same *a)
1148e95485f8SPeter Maydell {
1149e95485f8SPeter Maydell     if (!dc_isar_feature(aa32_simdfmac, s)) {
1150e95485f8SPeter Maydell         return false;
1151e95485f8SPeter Maydell     }
1152e95485f8SPeter Maydell 
1153e95485f8SPeter Maydell     if (a->size != 0) {
1154e95485f8SPeter Maydell         /* TODO fp16 support */
1155e95485f8SPeter Maydell         return false;
1156e95485f8SPeter Maydell     }
1157e95485f8SPeter Maydell 
1158e95485f8SPeter Maydell     return do_3same_fp(s, a, gen_VFMS_fp_3s, true);
1159e95485f8SPeter Maydell }
1160e95485f8SPeter Maydell 
1161ab978335SPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn)
1162ab978335SPeter Maydell {
1163ab978335SPeter Maydell     /* FP operations handled pairwise 32 bits at a time */
1164ab978335SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3;
1165ab978335SPeter Maydell     TCGv_ptr fpstatus;
1166ab978335SPeter Maydell 
1167ab978335SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1168ab978335SPeter Maydell         return false;
1169ab978335SPeter Maydell     }
1170ab978335SPeter Maydell 
1171ab978335SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1172ab978335SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1173ab978335SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1174ab978335SPeter Maydell         return false;
1175ab978335SPeter Maydell     }
1176ab978335SPeter Maydell 
1177ab978335SPeter Maydell     if (!vfp_access_check(s)) {
1178ab978335SPeter Maydell         return true;
1179ab978335SPeter Maydell     }
1180ab978335SPeter Maydell 
1181ab978335SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
1182ab978335SPeter Maydell 
1183ab978335SPeter Maydell     /*
1184ab978335SPeter Maydell      * Note that we have to be careful not to clobber the source operands
1185ab978335SPeter Maydell      * in the "vm == vd" case by storing the result of the first pass too
1186ab978335SPeter Maydell      * early. Since Q is 0 there are always just two passes, so instead
1187ab978335SPeter Maydell      * of a complicated loop over each pass we just unroll.
1188ab978335SPeter Maydell      */
1189ab978335SPeter Maydell     fpstatus = get_fpstatus_ptr(1);
1190ab978335SPeter Maydell     tmp = neon_load_reg(a->vn, 0);
1191ab978335SPeter Maydell     tmp2 = neon_load_reg(a->vn, 1);
1192ab978335SPeter Maydell     fn(tmp, tmp, tmp2, fpstatus);
1193ab978335SPeter Maydell     tcg_temp_free_i32(tmp2);
1194ab978335SPeter Maydell 
1195ab978335SPeter Maydell     tmp3 = neon_load_reg(a->vm, 0);
1196ab978335SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
1197ab978335SPeter Maydell     fn(tmp3, tmp3, tmp2, fpstatus);
1198ab978335SPeter Maydell     tcg_temp_free_i32(tmp2);
1199ab978335SPeter Maydell     tcg_temp_free_ptr(fpstatus);
1200ab978335SPeter Maydell 
1201ab978335SPeter Maydell     neon_store_reg(a->vd, 0, tmp);
1202ab978335SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
1203ab978335SPeter Maydell     return true;
1204ab978335SPeter Maydell }
1205ab978335SPeter Maydell 
1206ab978335SPeter Maydell /*
1207ab978335SPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
1208ab978335SPeter Maydell  * which is an architecture extension we don't implement yet.
1209ab978335SPeter Maydell  */
1210ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC)                                    \
1211ab978335SPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \
1212ab978335SPeter Maydell     {                                                               \
1213ab978335SPeter Maydell         if (a->size != 0) {                                         \
1214ab978335SPeter Maydell             /* TODO fp16 support */                                 \
1215ab978335SPeter Maydell             return false;                                           \
1216ab978335SPeter Maydell         }                                                           \
1217ab978335SPeter Maydell         return do_3same_fp_pair(s, a, FUNC);                        \
1218ab978335SPeter Maydell     }
1219ab978335SPeter Maydell 
1220ab978335SPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds)
1221ab978335SPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs)
1222ab978335SPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins)
1223d3c8c736SPeter Maydell 
1224d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
1225d3c8c736SPeter Maydell {
1226d3c8c736SPeter Maydell     /* Handle a 2-reg-shift insn which can be vectorized. */
1227d3c8c736SPeter Maydell     int vec_size = a->q ? 16 : 8;
1228d3c8c736SPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
1229d3c8c736SPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
1230d3c8c736SPeter Maydell 
1231d3c8c736SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1232d3c8c736SPeter Maydell         return false;
1233d3c8c736SPeter Maydell     }
1234d3c8c736SPeter Maydell 
1235d3c8c736SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1236d3c8c736SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1237d3c8c736SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1238d3c8c736SPeter Maydell         return false;
1239d3c8c736SPeter Maydell     }
1240d3c8c736SPeter Maydell 
1241d3c8c736SPeter Maydell     if ((a->vm | a->vd) & a->q) {
1242d3c8c736SPeter Maydell         return false;
1243d3c8c736SPeter Maydell     }
1244d3c8c736SPeter Maydell 
1245d3c8c736SPeter Maydell     if (!vfp_access_check(s)) {
1246d3c8c736SPeter Maydell         return true;
1247d3c8c736SPeter Maydell     }
1248d3c8c736SPeter Maydell 
1249d3c8c736SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size);
1250d3c8c736SPeter Maydell     return true;
1251d3c8c736SPeter Maydell }
1252d3c8c736SPeter Maydell 
1253d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC)                                              \
1254d3c8c736SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1255d3c8c736SPeter Maydell     {                                                                   \
1256d3c8c736SPeter Maydell         return do_vector_2sh(s, a, FUNC);                               \
1257d3c8c736SPeter Maydell     }                                                                   \
1258d3c8c736SPeter Maydell 
1259d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli)
1260d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli)
1261434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri)
1262434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra)
1263434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra)
1264434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr)
1265434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr)
1266434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra)
1267434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra)
126866432d6bSPeter Maydell 
126966432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a)
127066432d6bSPeter Maydell {
127166432d6bSPeter Maydell     /* Signed shift out of range results in all-sign-bits */
127266432d6bSPeter Maydell     a->shift = MIN(a->shift, (8 << a->size) - 1);
127366432d6bSPeter Maydell     return do_vector_2sh(s, a, tcg_gen_gvec_sari);
127466432d6bSPeter Maydell }
127566432d6bSPeter Maydell 
127666432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
127766432d6bSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
127866432d6bSPeter Maydell {
127966432d6bSPeter Maydell     tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0);
128066432d6bSPeter Maydell }
128166432d6bSPeter Maydell 
128266432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a)
128366432d6bSPeter Maydell {
128466432d6bSPeter Maydell     /* Shift out of range is architecturally valid and results in zero. */
128566432d6bSPeter Maydell     if (a->shift >= (8 << a->size)) {
128666432d6bSPeter Maydell         return do_vector_2sh(s, a, gen_zero_rd_2sh);
128766432d6bSPeter Maydell     } else {
128866432d6bSPeter Maydell         return do_vector_2sh(s, a, tcg_gen_gvec_shri);
128966432d6bSPeter Maydell     }
129066432d6bSPeter Maydell }
129137bfce81SPeter Maydell 
129237bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a,
129337bfce81SPeter Maydell                              NeonGenTwo64OpEnvFn *fn)
129437bfce81SPeter Maydell {
129537bfce81SPeter Maydell     /*
129637bfce81SPeter Maydell      * 2-reg-and-shift operations, size == 3 case, where the
129737bfce81SPeter Maydell      * function needs to be passed cpu_env.
129837bfce81SPeter Maydell      */
129937bfce81SPeter Maydell     TCGv_i64 constimm;
130037bfce81SPeter Maydell     int pass;
130137bfce81SPeter Maydell 
130237bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
130337bfce81SPeter Maydell         return false;
130437bfce81SPeter Maydell     }
130537bfce81SPeter Maydell 
130637bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
130737bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
130837bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
130937bfce81SPeter Maydell         return false;
131037bfce81SPeter Maydell     }
131137bfce81SPeter Maydell 
131237bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
131337bfce81SPeter Maydell         return false;
131437bfce81SPeter Maydell     }
131537bfce81SPeter Maydell 
131637bfce81SPeter Maydell     if (!vfp_access_check(s)) {
131737bfce81SPeter Maydell         return true;
131837bfce81SPeter Maydell     }
131937bfce81SPeter Maydell 
132037bfce81SPeter Maydell     /*
132137bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
132237bfce81SPeter Maydell      * by immediate using the variable shift operations.
132337bfce81SPeter Maydell      */
132437bfce81SPeter Maydell     constimm = tcg_const_i64(dup_const(a->size, a->shift));
132537bfce81SPeter Maydell 
132637bfce81SPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
132737bfce81SPeter Maydell         TCGv_i64 tmp = tcg_temp_new_i64();
132837bfce81SPeter Maydell 
132937bfce81SPeter Maydell         neon_load_reg64(tmp, a->vm + pass);
133037bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
133137bfce81SPeter Maydell         neon_store_reg64(tmp, a->vd + pass);
1332a4f67e18SPeter Maydell         tcg_temp_free_i64(tmp);
133337bfce81SPeter Maydell     }
133437bfce81SPeter Maydell     tcg_temp_free_i64(constimm);
133537bfce81SPeter Maydell     return true;
133637bfce81SPeter Maydell }
133737bfce81SPeter Maydell 
133837bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a,
133937bfce81SPeter Maydell                              NeonGenTwoOpEnvFn *fn)
134037bfce81SPeter Maydell {
134137bfce81SPeter Maydell     /*
134237bfce81SPeter Maydell      * 2-reg-and-shift operations, size < 3 case, where the
134337bfce81SPeter Maydell      * helper needs to be passed cpu_env.
134437bfce81SPeter Maydell      */
134537bfce81SPeter Maydell     TCGv_i32 constimm;
134637bfce81SPeter Maydell     int pass;
134737bfce81SPeter Maydell 
134837bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
134937bfce81SPeter Maydell         return false;
135037bfce81SPeter Maydell     }
135137bfce81SPeter Maydell 
135237bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
135337bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
135437bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
135537bfce81SPeter Maydell         return false;
135637bfce81SPeter Maydell     }
135737bfce81SPeter Maydell 
135837bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
135937bfce81SPeter Maydell         return false;
136037bfce81SPeter Maydell     }
136137bfce81SPeter Maydell 
136237bfce81SPeter Maydell     if (!vfp_access_check(s)) {
136337bfce81SPeter Maydell         return true;
136437bfce81SPeter Maydell     }
136537bfce81SPeter Maydell 
136637bfce81SPeter Maydell     /*
136737bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
136837bfce81SPeter Maydell      * by immediate using the variable shift operations.
136937bfce81SPeter Maydell      */
137037bfce81SPeter Maydell     constimm = tcg_const_i32(dup_const(a->size, a->shift));
137137bfce81SPeter Maydell 
137237bfce81SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
137337bfce81SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
137437bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
137537bfce81SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
137637bfce81SPeter Maydell     }
137737bfce81SPeter Maydell     tcg_temp_free_i32(constimm);
137837bfce81SPeter Maydell     return true;
137937bfce81SPeter Maydell }
138037bfce81SPeter Maydell 
138137bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC)                                       \
138237bfce81SPeter Maydell     static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \
138337bfce81SPeter Maydell     {                                                                   \
138437bfce81SPeter Maydell         return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64);      \
138537bfce81SPeter Maydell     }                                                                   \
138637bfce81SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
138737bfce81SPeter Maydell     {                                                                   \
138837bfce81SPeter Maydell         static NeonGenTwoOpEnvFn * const fns[] = {                      \
138937bfce81SPeter Maydell             gen_helper_neon_##FUNC##8,                                  \
139037bfce81SPeter Maydell             gen_helper_neon_##FUNC##16,                                 \
139137bfce81SPeter Maydell             gen_helper_neon_##FUNC##32,                                 \
139237bfce81SPeter Maydell         };                                                              \
139337bfce81SPeter Maydell         assert(a->size < ARRAY_SIZE(fns));                              \
139437bfce81SPeter Maydell         return do_2shift_env_32(s, a, fns[a->size]);                    \
139537bfce81SPeter Maydell     }
139637bfce81SPeter Maydell 
139737bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s)
139837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u)
139937bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s)
1400712182d3SPeter Maydell 
1401712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
1402712182d3SPeter Maydell                                 NeonGenTwo64OpFn *shiftfn,
1403712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1404712182d3SPeter Maydell {
1405712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size == 3 case */
1406712182d3SPeter Maydell     TCGv_i64 constimm, rm1, rm2;
1407712182d3SPeter Maydell     TCGv_i32 rd;
1408712182d3SPeter Maydell 
1409712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1410712182d3SPeter Maydell         return false;
1411712182d3SPeter Maydell     }
1412712182d3SPeter Maydell 
1413712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1414712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1415712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1416712182d3SPeter Maydell         return false;
1417712182d3SPeter Maydell     }
1418712182d3SPeter Maydell 
1419712182d3SPeter Maydell     if (a->vm & 1) {
1420712182d3SPeter Maydell         return false;
1421712182d3SPeter Maydell     }
1422712182d3SPeter Maydell 
1423712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1424712182d3SPeter Maydell         return true;
1425712182d3SPeter Maydell     }
1426712182d3SPeter Maydell 
1427712182d3SPeter Maydell     /*
1428712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1429712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count.
1430712182d3SPeter Maydell      */
1431712182d3SPeter Maydell     constimm = tcg_const_i64(-a->shift);
1432712182d3SPeter Maydell     rm1 = tcg_temp_new_i64();
1433712182d3SPeter Maydell     rm2 = tcg_temp_new_i64();
1434712182d3SPeter Maydell 
1435712182d3SPeter Maydell     /* Load both inputs first to avoid potential overwrite if rm == rd */
1436712182d3SPeter Maydell     neon_load_reg64(rm1, a->vm);
1437712182d3SPeter Maydell     neon_load_reg64(rm2, a->vm + 1);
1438712182d3SPeter Maydell 
1439712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1440712182d3SPeter Maydell     rd = tcg_temp_new_i32();
1441712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm1);
1442712182d3SPeter Maydell     neon_store_reg(a->vd, 0, rd);
1443712182d3SPeter Maydell 
1444712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1445712182d3SPeter Maydell     rd = tcg_temp_new_i32();
1446712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm2);
1447712182d3SPeter Maydell     neon_store_reg(a->vd, 1, rd);
1448712182d3SPeter Maydell 
1449712182d3SPeter Maydell     tcg_temp_free_i64(rm1);
1450712182d3SPeter Maydell     tcg_temp_free_i64(rm2);
1451712182d3SPeter Maydell     tcg_temp_free_i64(constimm);
1452712182d3SPeter Maydell 
1453712182d3SPeter Maydell     return true;
1454712182d3SPeter Maydell }
1455712182d3SPeter Maydell 
1456712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
1457712182d3SPeter Maydell                                 NeonGenTwoOpFn *shiftfn,
1458712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1459712182d3SPeter Maydell {
1460712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size < 3 case */
1461712182d3SPeter Maydell     TCGv_i32 constimm, rm1, rm2, rm3, rm4;
1462712182d3SPeter Maydell     TCGv_i64 rtmp;
1463712182d3SPeter Maydell     uint32_t imm;
1464712182d3SPeter Maydell 
1465712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1466712182d3SPeter Maydell         return false;
1467712182d3SPeter Maydell     }
1468712182d3SPeter Maydell 
1469712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1470712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1471712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1472712182d3SPeter Maydell         return false;
1473712182d3SPeter Maydell     }
1474712182d3SPeter Maydell 
1475712182d3SPeter Maydell     if (a->vm & 1) {
1476712182d3SPeter Maydell         return false;
1477712182d3SPeter Maydell     }
1478712182d3SPeter Maydell 
1479712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1480712182d3SPeter Maydell         return true;
1481712182d3SPeter Maydell     }
1482712182d3SPeter Maydell 
1483712182d3SPeter Maydell     /*
1484712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1485712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count
1486712182d3SPeter Maydell      * duplicated into each lane of the immediate value.
1487712182d3SPeter Maydell      */
1488712182d3SPeter Maydell     if (a->size == 1) {
1489712182d3SPeter Maydell         imm = (uint16_t)(-a->shift);
1490712182d3SPeter Maydell         imm |= imm << 16;
1491712182d3SPeter Maydell     } else {
1492712182d3SPeter Maydell         /* size == 2 */
1493712182d3SPeter Maydell         imm = -a->shift;
1494712182d3SPeter Maydell     }
1495712182d3SPeter Maydell     constimm = tcg_const_i32(imm);
1496712182d3SPeter Maydell 
1497712182d3SPeter Maydell     /* Load all inputs first to avoid potential overwrite */
1498712182d3SPeter Maydell     rm1 = neon_load_reg(a->vm, 0);
1499712182d3SPeter Maydell     rm2 = neon_load_reg(a->vm, 1);
1500712182d3SPeter Maydell     rm3 = neon_load_reg(a->vm + 1, 0);
1501712182d3SPeter Maydell     rm4 = neon_load_reg(a->vm + 1, 1);
1502712182d3SPeter Maydell     rtmp = tcg_temp_new_i64();
1503712182d3SPeter Maydell 
1504712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1505712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1506712182d3SPeter Maydell 
1507712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
1508712182d3SPeter Maydell     tcg_temp_free_i32(rm2);
1509712182d3SPeter Maydell 
1510712182d3SPeter Maydell     narrowfn(rm1, cpu_env, rtmp);
1511712182d3SPeter Maydell     neon_store_reg(a->vd, 0, rm1);
1512712182d3SPeter Maydell 
1513712182d3SPeter Maydell     shiftfn(rm3, rm3, constimm);
1514712182d3SPeter Maydell     shiftfn(rm4, rm4, constimm);
1515712182d3SPeter Maydell     tcg_temp_free_i32(constimm);
1516712182d3SPeter Maydell 
1517712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
1518712182d3SPeter Maydell     tcg_temp_free_i32(rm4);
1519712182d3SPeter Maydell 
1520712182d3SPeter Maydell     narrowfn(rm3, cpu_env, rtmp);
1521712182d3SPeter Maydell     tcg_temp_free_i64(rtmp);
1522712182d3SPeter Maydell     neon_store_reg(a->vd, 1, rm3);
1523712182d3SPeter Maydell     return true;
1524712182d3SPeter Maydell }
1525712182d3SPeter Maydell 
1526712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC)                               \
1527712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1528712182d3SPeter Maydell     {                                                                   \
1529712182d3SPeter Maydell         return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC);             \
1530712182d3SPeter Maydell     }
1531712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC)                               \
1532712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1533712182d3SPeter Maydell     {                                                                   \
1534712182d3SPeter Maydell         return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC);             \
1535712182d3SPeter Maydell     }
1536712182d3SPeter Maydell 
1537712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1538712182d3SPeter Maydell {
1539712182d3SPeter Maydell     tcg_gen_extrl_i64_i32(dest, src);
1540712182d3SPeter Maydell }
1541712182d3SPeter Maydell 
1542712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1543712182d3SPeter Maydell {
1544712182d3SPeter Maydell     gen_helper_neon_narrow_u16(dest, src);
1545712182d3SPeter Maydell }
1546712182d3SPeter Maydell 
1547712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1548712182d3SPeter Maydell {
1549712182d3SPeter Maydell     gen_helper_neon_narrow_u8(dest, src);
1550712182d3SPeter Maydell }
1551712182d3SPeter Maydell 
1552712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32)
1553712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16)
1554712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8)
1555712182d3SPeter Maydell 
1556712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32)
1557712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16)
1558712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8)
1559712182d3SPeter Maydell 
1560712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32)
1561712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16)
1562712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8)
1563712182d3SPeter Maydell 
1564712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32)
1565712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16)
1566712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8)
1567b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32)
1568b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16)
1569b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8)
1570b4a3a77bSPeter Maydell 
1571b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32)
1572b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16)
1573b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8)
1574b4a3a77bSPeter Maydell 
1575b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32)
1576b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16)
1577b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8)
1578b4a3a77bSPeter Maydell 
1579b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32)
1580b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16)
1581b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8)
1582968bf842SPeter Maydell 
1583968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
1584968bf842SPeter Maydell                          NeonGenWidenFn *widenfn, bool u)
1585968bf842SPeter Maydell {
1586968bf842SPeter Maydell     TCGv_i64 tmp;
1587968bf842SPeter Maydell     TCGv_i32 rm0, rm1;
1588968bf842SPeter Maydell     uint64_t widen_mask = 0;
1589968bf842SPeter Maydell 
1590968bf842SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1591968bf842SPeter Maydell         return false;
1592968bf842SPeter Maydell     }
1593968bf842SPeter Maydell 
1594968bf842SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1595968bf842SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1596968bf842SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1597968bf842SPeter Maydell         return false;
1598968bf842SPeter Maydell     }
1599968bf842SPeter Maydell 
1600968bf842SPeter Maydell     if (a->vd & 1) {
1601968bf842SPeter Maydell         return false;
1602968bf842SPeter Maydell     }
1603968bf842SPeter Maydell 
1604968bf842SPeter Maydell     if (!vfp_access_check(s)) {
1605968bf842SPeter Maydell         return true;
1606968bf842SPeter Maydell     }
1607968bf842SPeter Maydell 
1608968bf842SPeter Maydell     /*
1609968bf842SPeter Maydell      * This is a widen-and-shift operation. The shift is always less
1610968bf842SPeter Maydell      * than the width of the source type, so after widening the input
1611968bf842SPeter Maydell      * vector we can simply shift the whole 64-bit widened register,
1612968bf842SPeter Maydell      * and then clear the potential overflow bits resulting from left
1613968bf842SPeter Maydell      * bits of the narrow input appearing as right bits of the left
1614968bf842SPeter Maydell      * neighbour narrow input. Calculate a mask of bits to clear.
1615968bf842SPeter Maydell      */
1616968bf842SPeter Maydell     if ((a->shift != 0) && (a->size < 2 || u)) {
1617968bf842SPeter Maydell         int esize = 8 << a->size;
1618968bf842SPeter Maydell         widen_mask = MAKE_64BIT_MASK(0, esize);
1619968bf842SPeter Maydell         widen_mask >>= esize - a->shift;
1620968bf842SPeter Maydell         widen_mask = dup_const(a->size + 1, widen_mask);
1621968bf842SPeter Maydell     }
1622968bf842SPeter Maydell 
1623968bf842SPeter Maydell     rm0 = neon_load_reg(a->vm, 0);
1624968bf842SPeter Maydell     rm1 = neon_load_reg(a->vm, 1);
1625968bf842SPeter Maydell     tmp = tcg_temp_new_i64();
1626968bf842SPeter Maydell 
1627968bf842SPeter Maydell     widenfn(tmp, rm0);
16289593a398SPeter Maydell     tcg_temp_free_i32(rm0);
1629968bf842SPeter Maydell     if (a->shift != 0) {
1630968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1631968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1632968bf842SPeter Maydell     }
1633968bf842SPeter Maydell     neon_store_reg64(tmp, a->vd);
1634968bf842SPeter Maydell 
1635968bf842SPeter Maydell     widenfn(tmp, rm1);
16369593a398SPeter Maydell     tcg_temp_free_i32(rm1);
1637968bf842SPeter Maydell     if (a->shift != 0) {
1638968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1639968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1640968bf842SPeter Maydell     }
1641968bf842SPeter Maydell     neon_store_reg64(tmp, a->vd + 1);
1642968bf842SPeter Maydell     tcg_temp_free_i64(tmp);
1643968bf842SPeter Maydell     return true;
1644968bf842SPeter Maydell }
1645968bf842SPeter Maydell 
1646968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a)
1647968bf842SPeter Maydell {
1648448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1649968bf842SPeter Maydell         gen_helper_neon_widen_s8,
1650968bf842SPeter Maydell         gen_helper_neon_widen_s16,
1651968bf842SPeter Maydell         tcg_gen_ext_i32_i64,
1652968bf842SPeter Maydell     };
1653968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], false);
1654968bf842SPeter Maydell }
1655968bf842SPeter Maydell 
1656968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
1657968bf842SPeter Maydell {
1658448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1659968bf842SPeter Maydell         gen_helper_neon_widen_u8,
1660968bf842SPeter Maydell         gen_helper_neon_widen_u16,
1661968bf842SPeter Maydell         tcg_gen_extu_i32_i64,
1662968bf842SPeter Maydell     };
1663968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], true);
1664968bf842SPeter Maydell }
16653da26f11SPeter Maydell 
16663da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
16675de3fd04SPeter Maydell                       NeonGenTwoSingleOpFn *fn)
16683da26f11SPeter Maydell {
16693da26f11SPeter Maydell     /* FP operations in 2-reg-and-shift group */
16703da26f11SPeter Maydell     TCGv_i32 tmp, shiftv;
16713da26f11SPeter Maydell     TCGv_ptr fpstatus;
16723da26f11SPeter Maydell     int pass;
16733da26f11SPeter Maydell 
16743da26f11SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
16753da26f11SPeter Maydell         return false;
16763da26f11SPeter Maydell     }
16773da26f11SPeter Maydell 
16783da26f11SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
16793da26f11SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
16803da26f11SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
16813da26f11SPeter Maydell         return false;
16823da26f11SPeter Maydell     }
16833da26f11SPeter Maydell 
16843da26f11SPeter Maydell     if ((a->vm | a->vd) & a->q) {
16853da26f11SPeter Maydell         return false;
16863da26f11SPeter Maydell     }
16873da26f11SPeter Maydell 
16883da26f11SPeter Maydell     if (!vfp_access_check(s)) {
16893da26f11SPeter Maydell         return true;
16903da26f11SPeter Maydell     }
16913da26f11SPeter Maydell 
16923da26f11SPeter Maydell     fpstatus = get_fpstatus_ptr(1);
16933da26f11SPeter Maydell     shiftv = tcg_const_i32(a->shift);
16943da26f11SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
16953da26f11SPeter Maydell         tmp = neon_load_reg(a->vm, pass);
16963da26f11SPeter Maydell         fn(tmp, tmp, shiftv, fpstatus);
16973da26f11SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
16983da26f11SPeter Maydell     }
16993da26f11SPeter Maydell     tcg_temp_free_ptr(fpstatus);
17003da26f11SPeter Maydell     tcg_temp_free_i32(shiftv);
17013da26f11SPeter Maydell     return true;
17023da26f11SPeter Maydell }
17033da26f11SPeter Maydell 
17043da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC)                                           \
17053da26f11SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
17063da26f11SPeter Maydell     {                                                                   \
17073da26f11SPeter Maydell         return do_fp_2sh(s, a, FUNC);                                   \
17083da26f11SPeter Maydell     }
17093da26f11SPeter Maydell 
17103da26f11SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos)
17113da26f11SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos)
17123da26f11SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero)
17133da26f11SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero)
17142c35a39eSPeter Maydell 
17152c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
17162c35a39eSPeter Maydell {
17172c35a39eSPeter Maydell     /*
17182c35a39eSPeter Maydell      * Expand the encoded constant.
17192c35a39eSPeter Maydell      * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
17202c35a39eSPeter Maydell      * We choose to not special-case this and will behave as if a
17212c35a39eSPeter Maydell      * valid constant encoding of 0 had been given.
17222c35a39eSPeter Maydell      * cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
17232c35a39eSPeter Maydell      */
17242c35a39eSPeter Maydell     switch (cmode) {
17252c35a39eSPeter Maydell     case 0: case 1:
17262c35a39eSPeter Maydell         /* no-op */
17272c35a39eSPeter Maydell         break;
17282c35a39eSPeter Maydell     case 2: case 3:
17292c35a39eSPeter Maydell         imm <<= 8;
17302c35a39eSPeter Maydell         break;
17312c35a39eSPeter Maydell     case 4: case 5:
17322c35a39eSPeter Maydell         imm <<= 16;
17332c35a39eSPeter Maydell         break;
17342c35a39eSPeter Maydell     case 6: case 7:
17352c35a39eSPeter Maydell         imm <<= 24;
17362c35a39eSPeter Maydell         break;
17372c35a39eSPeter Maydell     case 8: case 9:
17382c35a39eSPeter Maydell         imm |= imm << 16;
17392c35a39eSPeter Maydell         break;
17402c35a39eSPeter Maydell     case 10: case 11:
17412c35a39eSPeter Maydell         imm = (imm << 8) | (imm << 24);
17422c35a39eSPeter Maydell         break;
17432c35a39eSPeter Maydell     case 12:
17442c35a39eSPeter Maydell         imm = (imm << 8) | 0xff;
17452c35a39eSPeter Maydell         break;
17462c35a39eSPeter Maydell     case 13:
17472c35a39eSPeter Maydell         imm = (imm << 16) | 0xffff;
17482c35a39eSPeter Maydell         break;
17492c35a39eSPeter Maydell     case 14:
17502c35a39eSPeter Maydell         if (op) {
17512c35a39eSPeter Maydell             /*
17522c35a39eSPeter Maydell              * This is the only case where the top and bottom 32 bits
17532c35a39eSPeter Maydell              * of the encoded constant differ.
17542c35a39eSPeter Maydell              */
17552c35a39eSPeter Maydell             uint64_t imm64 = 0;
17562c35a39eSPeter Maydell             int n;
17572c35a39eSPeter Maydell 
17582c35a39eSPeter Maydell             for (n = 0; n < 8; n++) {
17592c35a39eSPeter Maydell                 if (imm & (1 << n)) {
17602c35a39eSPeter Maydell                     imm64 |= (0xffULL << (n * 8));
17612c35a39eSPeter Maydell                 }
17622c35a39eSPeter Maydell             }
17632c35a39eSPeter Maydell             return imm64;
17642c35a39eSPeter Maydell         }
17652c35a39eSPeter Maydell         imm |= (imm << 8) | (imm << 16) | (imm << 24);
17662c35a39eSPeter Maydell         break;
17672c35a39eSPeter Maydell     case 15:
17682c35a39eSPeter Maydell         imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
17692c35a39eSPeter Maydell             | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
17702c35a39eSPeter Maydell         break;
17712c35a39eSPeter Maydell     }
17722c35a39eSPeter Maydell     if (op) {
17732c35a39eSPeter Maydell         imm = ~imm;
17742c35a39eSPeter Maydell     }
17752c35a39eSPeter Maydell     return dup_const(MO_32, imm);
17762c35a39eSPeter Maydell }
17772c35a39eSPeter Maydell 
17782c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
17792c35a39eSPeter Maydell                         GVecGen2iFn *fn)
17802c35a39eSPeter Maydell {
17812c35a39eSPeter Maydell     uint64_t imm;
17822c35a39eSPeter Maydell     int reg_ofs, vec_size;
17832c35a39eSPeter Maydell 
17842c35a39eSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
17852c35a39eSPeter Maydell         return false;
17862c35a39eSPeter Maydell     }
17872c35a39eSPeter Maydell 
17882c35a39eSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
17892c35a39eSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
17902c35a39eSPeter Maydell         return false;
17912c35a39eSPeter Maydell     }
17922c35a39eSPeter Maydell 
17932c35a39eSPeter Maydell     if (a->vd & a->q) {
17942c35a39eSPeter Maydell         return false;
17952c35a39eSPeter Maydell     }
17962c35a39eSPeter Maydell 
17972c35a39eSPeter Maydell     if (!vfp_access_check(s)) {
17982c35a39eSPeter Maydell         return true;
17992c35a39eSPeter Maydell     }
18002c35a39eSPeter Maydell 
18012c35a39eSPeter Maydell     reg_ofs = neon_reg_offset(a->vd, 0);
18022c35a39eSPeter Maydell     vec_size = a->q ? 16 : 8;
18032c35a39eSPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
18042c35a39eSPeter Maydell 
18052c35a39eSPeter Maydell     fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size);
18062c35a39eSPeter Maydell     return true;
18072c35a39eSPeter Maydell }
18082c35a39eSPeter Maydell 
18092c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs,
18102c35a39eSPeter Maydell                         int64_t c, uint32_t oprsz, uint32_t maxsz)
18112c35a39eSPeter Maydell {
18122c35a39eSPeter Maydell     tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
18132c35a39eSPeter Maydell }
18142c35a39eSPeter Maydell 
18152c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a)
18162c35a39eSPeter Maydell {
18172c35a39eSPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
18182c35a39eSPeter Maydell     GVecGen2iFn *fn;
18192c35a39eSPeter Maydell 
18202c35a39eSPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
18212c35a39eSPeter Maydell         /* for op=1, the imm will be inverted, so BIC becomes AND. */
18222c35a39eSPeter Maydell         fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
18232c35a39eSPeter Maydell     } else {
18242c35a39eSPeter Maydell         /* There is one unallocated cmode/op combination in this space */
18252c35a39eSPeter Maydell         if (a->cmode == 15 && a->op == 1) {
18262c35a39eSPeter Maydell             return false;
18272c35a39eSPeter Maydell         }
18282c35a39eSPeter Maydell         fn = gen_VMOV_1r;
18292c35a39eSPeter Maydell     }
18302c35a39eSPeter Maydell     return do_1reg_imm(s, a, fn);
18312c35a39eSPeter Maydell }
1832b28be095SPeter Maydell 
1833b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
1834b28be095SPeter Maydell                            NeonGenWidenFn *widenfn,
1835b28be095SPeter Maydell                            NeonGenTwo64OpFn *opfn,
1836b28be095SPeter Maydell                            bool src1_wide)
1837b28be095SPeter Maydell {
1838b28be095SPeter Maydell     /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */
1839b28be095SPeter Maydell     TCGv_i64 rn0_64, rn1_64, rm_64;
1840b28be095SPeter Maydell     TCGv_i32 rm;
1841b28be095SPeter Maydell 
1842b28be095SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1843b28be095SPeter Maydell         return false;
1844b28be095SPeter Maydell     }
1845b28be095SPeter Maydell 
1846b28be095SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1847b28be095SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1848b28be095SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1849b28be095SPeter Maydell         return false;
1850b28be095SPeter Maydell     }
1851b28be095SPeter Maydell 
1852b28be095SPeter Maydell     if (!widenfn || !opfn) {
1853b28be095SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
1854b28be095SPeter Maydell         return false;
1855b28be095SPeter Maydell     }
1856b28be095SPeter Maydell 
1857b28be095SPeter Maydell     if ((a->vd & 1) || (src1_wide && (a->vn & 1))) {
1858b28be095SPeter Maydell         return false;
1859b28be095SPeter Maydell     }
1860b28be095SPeter Maydell 
1861b28be095SPeter Maydell     if (!vfp_access_check(s)) {
1862b28be095SPeter Maydell         return true;
1863b28be095SPeter Maydell     }
1864b28be095SPeter Maydell 
1865b28be095SPeter Maydell     rn0_64 = tcg_temp_new_i64();
1866b28be095SPeter Maydell     rn1_64 = tcg_temp_new_i64();
1867b28be095SPeter Maydell     rm_64 = tcg_temp_new_i64();
1868b28be095SPeter Maydell 
1869b28be095SPeter Maydell     if (src1_wide) {
1870b28be095SPeter Maydell         neon_load_reg64(rn0_64, a->vn);
1871b28be095SPeter Maydell     } else {
1872b28be095SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, 0);
1873b28be095SPeter Maydell         widenfn(rn0_64, tmp);
1874b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1875b28be095SPeter Maydell     }
1876b28be095SPeter Maydell     rm = neon_load_reg(a->vm, 0);
1877b28be095SPeter Maydell 
1878b28be095SPeter Maydell     widenfn(rm_64, rm);
1879b28be095SPeter Maydell     tcg_temp_free_i32(rm);
1880b28be095SPeter Maydell     opfn(rn0_64, rn0_64, rm_64);
1881b28be095SPeter Maydell 
1882b28be095SPeter Maydell     /*
1883b28be095SPeter Maydell      * Load second pass inputs before storing the first pass result, to
1884b28be095SPeter Maydell      * avoid incorrect results if a narrow input overlaps with the result.
1885b28be095SPeter Maydell      */
1886b28be095SPeter Maydell     if (src1_wide) {
1887b28be095SPeter Maydell         neon_load_reg64(rn1_64, a->vn + 1);
1888b28be095SPeter Maydell     } else {
1889b28be095SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, 1);
1890b28be095SPeter Maydell         widenfn(rn1_64, tmp);
1891b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1892b28be095SPeter Maydell     }
1893b28be095SPeter Maydell     rm = neon_load_reg(a->vm, 1);
1894b28be095SPeter Maydell 
1895b28be095SPeter Maydell     neon_store_reg64(rn0_64, a->vd);
1896b28be095SPeter Maydell 
1897b28be095SPeter Maydell     widenfn(rm_64, rm);
1898b28be095SPeter Maydell     tcg_temp_free_i32(rm);
1899b28be095SPeter Maydell     opfn(rn1_64, rn1_64, rm_64);
1900b28be095SPeter Maydell     neon_store_reg64(rn1_64, a->vd + 1);
1901b28be095SPeter Maydell 
1902b28be095SPeter Maydell     tcg_temp_free_i64(rn0_64);
1903b28be095SPeter Maydell     tcg_temp_free_i64(rn1_64);
1904b28be095SPeter Maydell     tcg_temp_free_i64(rm_64);
1905b28be095SPeter Maydell 
1906b28be095SPeter Maydell     return true;
1907b28be095SPeter Maydell }
1908b28be095SPeter Maydell 
1909b28be095SPeter Maydell #define DO_PREWIDEN(INSN, S, EXT, OP, SRC1WIDE)                         \
1910b28be095SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
1911b28be095SPeter Maydell     {                                                                   \
1912b28be095SPeter Maydell         static NeonGenWidenFn * const widenfn[] = {                     \
1913b28be095SPeter Maydell             gen_helper_neon_widen_##S##8,                               \
1914b28be095SPeter Maydell             gen_helper_neon_widen_##S##16,                              \
1915b28be095SPeter Maydell             tcg_gen_##EXT##_i32_i64,                                    \
1916b28be095SPeter Maydell             NULL,                                                       \
1917b28be095SPeter Maydell         };                                                              \
1918b28be095SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
1919b28be095SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
1920b28be095SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
1921b28be095SPeter Maydell             tcg_gen_##OP##_i64,                                         \
1922b28be095SPeter Maydell             NULL,                                                       \
1923b28be095SPeter Maydell         };                                                              \
1924b28be095SPeter Maydell         return do_prewiden_3d(s, a, widenfn[a->size],                   \
1925b28be095SPeter Maydell                               addfn[a->size], SRC1WIDE);                \
1926b28be095SPeter Maydell     }
1927b28be095SPeter Maydell 
1928b28be095SPeter Maydell DO_PREWIDEN(VADDL_S, s, ext, add, false)
1929b28be095SPeter Maydell DO_PREWIDEN(VADDL_U, u, extu, add, false)
1930b28be095SPeter Maydell DO_PREWIDEN(VSUBL_S, s, ext, sub, false)
1931b28be095SPeter Maydell DO_PREWIDEN(VSUBL_U, u, extu, sub, false)
1932b28be095SPeter Maydell DO_PREWIDEN(VADDW_S, s, ext, add, true)
1933b28be095SPeter Maydell DO_PREWIDEN(VADDW_U, u, extu, add, true)
1934b28be095SPeter Maydell DO_PREWIDEN(VSUBW_S, s, ext, sub, true)
1935b28be095SPeter Maydell DO_PREWIDEN(VSUBW_U, u, extu, sub, true)
19360fa1ab03SPeter Maydell 
19370fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
19380fa1ab03SPeter Maydell                          NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn)
19390fa1ab03SPeter Maydell {
19400fa1ab03SPeter Maydell     /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */
19410fa1ab03SPeter Maydell     TCGv_i64 rn_64, rm_64;
19420fa1ab03SPeter Maydell     TCGv_i32 rd0, rd1;
19430fa1ab03SPeter Maydell 
19440fa1ab03SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
19450fa1ab03SPeter Maydell         return false;
19460fa1ab03SPeter Maydell     }
19470fa1ab03SPeter Maydell 
19480fa1ab03SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
19490fa1ab03SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
19500fa1ab03SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
19510fa1ab03SPeter Maydell         return false;
19520fa1ab03SPeter Maydell     }
19530fa1ab03SPeter Maydell 
19540fa1ab03SPeter Maydell     if (!opfn || !narrowfn) {
19550fa1ab03SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
19560fa1ab03SPeter Maydell         return false;
19570fa1ab03SPeter Maydell     }
19580fa1ab03SPeter Maydell 
19590fa1ab03SPeter Maydell     if ((a->vn | a->vm) & 1) {
19600fa1ab03SPeter Maydell         return false;
19610fa1ab03SPeter Maydell     }
19620fa1ab03SPeter Maydell 
19630fa1ab03SPeter Maydell     if (!vfp_access_check(s)) {
19640fa1ab03SPeter Maydell         return true;
19650fa1ab03SPeter Maydell     }
19660fa1ab03SPeter Maydell 
19670fa1ab03SPeter Maydell     rn_64 = tcg_temp_new_i64();
19680fa1ab03SPeter Maydell     rm_64 = tcg_temp_new_i64();
19690fa1ab03SPeter Maydell     rd0 = tcg_temp_new_i32();
19700fa1ab03SPeter Maydell     rd1 = tcg_temp_new_i32();
19710fa1ab03SPeter Maydell 
19720fa1ab03SPeter Maydell     neon_load_reg64(rn_64, a->vn);
19730fa1ab03SPeter Maydell     neon_load_reg64(rm_64, a->vm);
19740fa1ab03SPeter Maydell 
19750fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
19760fa1ab03SPeter Maydell 
19770fa1ab03SPeter Maydell     narrowfn(rd0, rn_64);
19780fa1ab03SPeter Maydell 
19790fa1ab03SPeter Maydell     neon_load_reg64(rn_64, a->vn + 1);
19800fa1ab03SPeter Maydell     neon_load_reg64(rm_64, a->vm + 1);
19810fa1ab03SPeter Maydell 
19820fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
19830fa1ab03SPeter Maydell 
19840fa1ab03SPeter Maydell     narrowfn(rd1, rn_64);
19850fa1ab03SPeter Maydell 
19860fa1ab03SPeter Maydell     neon_store_reg(a->vd, 0, rd0);
19870fa1ab03SPeter Maydell     neon_store_reg(a->vd, 1, rd1);
19880fa1ab03SPeter Maydell 
19890fa1ab03SPeter Maydell     tcg_temp_free_i64(rn_64);
19900fa1ab03SPeter Maydell     tcg_temp_free_i64(rm_64);
19910fa1ab03SPeter Maydell 
19920fa1ab03SPeter Maydell     return true;
19930fa1ab03SPeter Maydell }
19940fa1ab03SPeter Maydell 
19950fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP)                       \
19960fa1ab03SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
19970fa1ab03SPeter Maydell     {                                                                   \
19980fa1ab03SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
19990fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
20000fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
20010fa1ab03SPeter Maydell             tcg_gen_##OP##_i64,                                         \
20020fa1ab03SPeter Maydell             NULL,                                                       \
20030fa1ab03SPeter Maydell         };                                                              \
20040fa1ab03SPeter Maydell         static NeonGenNarrowFn * const narrowfn[] = {                   \
20050fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u8,                     \
20060fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u16,                    \
20070fa1ab03SPeter Maydell             EXTOP,                                                      \
20080fa1ab03SPeter Maydell             NULL,                                                       \
20090fa1ab03SPeter Maydell         };                                                              \
20100fa1ab03SPeter Maydell         return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]);   \
20110fa1ab03SPeter Maydell     }
20120fa1ab03SPeter Maydell 
20130fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn)
20140fa1ab03SPeter Maydell {
20150fa1ab03SPeter Maydell     tcg_gen_addi_i64(rn, rn, 1u << 31);
20160fa1ab03SPeter Maydell     tcg_gen_extrh_i64_i32(rd, rn);
20170fa1ab03SPeter Maydell }
20180fa1ab03SPeter Maydell 
20190fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32)
20200fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32)
20210fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32)
20220fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32)
2023f5b28401SPeter Maydell 
2024f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a,
2025f5b28401SPeter Maydell                        NeonGenTwoOpWidenFn *opfn,
2026f5b28401SPeter Maydell                        NeonGenTwo64OpFn *accfn)
2027f5b28401SPeter Maydell {
2028f5b28401SPeter Maydell     /*
2029f5b28401SPeter Maydell      * 3-regs different lengths, long operations.
2030f5b28401SPeter Maydell      * These perform an operation on two inputs that returns a double-width
2031f5b28401SPeter Maydell      * result, and then possibly perform an accumulation operation of
2032f5b28401SPeter Maydell      * that result into the double-width destination.
2033f5b28401SPeter Maydell      */
2034f5b28401SPeter Maydell     TCGv_i64 rd0, rd1, tmp;
2035f5b28401SPeter Maydell     TCGv_i32 rn, rm;
2036f5b28401SPeter Maydell 
2037f5b28401SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2038f5b28401SPeter Maydell         return false;
2039f5b28401SPeter Maydell     }
2040f5b28401SPeter Maydell 
2041f5b28401SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2042f5b28401SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2043f5b28401SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2044f5b28401SPeter Maydell         return false;
2045f5b28401SPeter Maydell     }
2046f5b28401SPeter Maydell 
2047f5b28401SPeter Maydell     if (!opfn) {
2048f5b28401SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
2049f5b28401SPeter Maydell         return false;
2050f5b28401SPeter Maydell     }
2051f5b28401SPeter Maydell 
2052f5b28401SPeter Maydell     if (a->vd & 1) {
2053f5b28401SPeter Maydell         return false;
2054f5b28401SPeter Maydell     }
2055f5b28401SPeter Maydell 
2056f5b28401SPeter Maydell     if (!vfp_access_check(s)) {
2057f5b28401SPeter Maydell         return true;
2058f5b28401SPeter Maydell     }
2059f5b28401SPeter Maydell 
2060f5b28401SPeter Maydell     rd0 = tcg_temp_new_i64();
2061f5b28401SPeter Maydell     rd1 = tcg_temp_new_i64();
2062f5b28401SPeter Maydell 
2063f5b28401SPeter Maydell     rn = neon_load_reg(a->vn, 0);
2064f5b28401SPeter Maydell     rm = neon_load_reg(a->vm, 0);
2065f5b28401SPeter Maydell     opfn(rd0, rn, rm);
2066f5b28401SPeter Maydell     tcg_temp_free_i32(rn);
2067f5b28401SPeter Maydell     tcg_temp_free_i32(rm);
2068f5b28401SPeter Maydell 
2069f5b28401SPeter Maydell     rn = neon_load_reg(a->vn, 1);
2070f5b28401SPeter Maydell     rm = neon_load_reg(a->vm, 1);
2071f5b28401SPeter Maydell     opfn(rd1, rn, rm);
2072f5b28401SPeter Maydell     tcg_temp_free_i32(rn);
2073f5b28401SPeter Maydell     tcg_temp_free_i32(rm);
2074f5b28401SPeter Maydell 
2075f5b28401SPeter Maydell     /* Don't store results until after all loads: they might overlap */
2076f5b28401SPeter Maydell     if (accfn) {
2077f5b28401SPeter Maydell         tmp = tcg_temp_new_i64();
2078f5b28401SPeter Maydell         neon_load_reg64(tmp, a->vd);
2079f5b28401SPeter Maydell         accfn(tmp, tmp, rd0);
2080f5b28401SPeter Maydell         neon_store_reg64(tmp, a->vd);
2081f5b28401SPeter Maydell         neon_load_reg64(tmp, a->vd + 1);
2082f5b28401SPeter Maydell         accfn(tmp, tmp, rd1);
2083f5b28401SPeter Maydell         neon_store_reg64(tmp, a->vd + 1);
2084f5b28401SPeter Maydell         tcg_temp_free_i64(tmp);
2085f5b28401SPeter Maydell     } else {
2086f5b28401SPeter Maydell         neon_store_reg64(rd0, a->vd);
2087f5b28401SPeter Maydell         neon_store_reg64(rd1, a->vd + 1);
2088f5b28401SPeter Maydell     }
2089f5b28401SPeter Maydell 
2090f5b28401SPeter Maydell     tcg_temp_free_i64(rd0);
2091f5b28401SPeter Maydell     tcg_temp_free_i64(rd1);
2092f5b28401SPeter Maydell 
2093f5b28401SPeter Maydell     return true;
2094f5b28401SPeter Maydell }
2095f5b28401SPeter Maydell 
2096f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a)
2097f5b28401SPeter Maydell {
2098f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2099f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2100f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2101f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2102f5b28401SPeter Maydell         NULL,
2103f5b28401SPeter Maydell     };
2104f5b28401SPeter Maydell 
2105f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2106f5b28401SPeter Maydell }
2107f5b28401SPeter Maydell 
2108f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a)
2109f5b28401SPeter Maydell {
2110f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2111f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2112f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2113f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2114f5b28401SPeter Maydell         NULL,
2115f5b28401SPeter Maydell     };
2116f5b28401SPeter Maydell 
2117f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2118f5b28401SPeter Maydell }
2119f5b28401SPeter Maydell 
2120f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a)
2121f5b28401SPeter Maydell {
2122f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2123f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2124f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2125f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2126f5b28401SPeter Maydell         NULL,
2127f5b28401SPeter Maydell     };
2128f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2129f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2130f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2131f5b28401SPeter Maydell         tcg_gen_add_i64,
2132f5b28401SPeter Maydell         NULL,
2133f5b28401SPeter Maydell     };
2134f5b28401SPeter Maydell 
2135f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2136f5b28401SPeter Maydell }
2137f5b28401SPeter Maydell 
2138f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
2139f5b28401SPeter Maydell {
2140f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2141f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2142f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2143f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2144f5b28401SPeter Maydell         NULL,
2145f5b28401SPeter Maydell     };
2146f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2147f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2148f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2149f5b28401SPeter Maydell         tcg_gen_add_i64,
2150f5b28401SPeter Maydell         NULL,
2151f5b28401SPeter Maydell     };
2152f5b28401SPeter Maydell 
2153f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2154f5b28401SPeter Maydell }
21553a1d9eb0SPeter Maydell 
21563a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
21573a1d9eb0SPeter Maydell {
21583a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
21593a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
21603a1d9eb0SPeter Maydell 
21613a1d9eb0SPeter Maydell     tcg_gen_muls2_i32(lo, hi, rn, rm);
21623a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
21633a1d9eb0SPeter Maydell 
21643a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
21653a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
21663a1d9eb0SPeter Maydell }
21673a1d9eb0SPeter Maydell 
21683a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
21693a1d9eb0SPeter Maydell {
21703a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
21713a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
21723a1d9eb0SPeter Maydell 
21733a1d9eb0SPeter Maydell     tcg_gen_mulu2_i32(lo, hi, rn, rm);
21743a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
21753a1d9eb0SPeter Maydell 
21763a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
21773a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
21783a1d9eb0SPeter Maydell }
21793a1d9eb0SPeter Maydell 
21803a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a)
21813a1d9eb0SPeter Maydell {
21823a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
21833a1d9eb0SPeter Maydell         gen_helper_neon_mull_s8,
21843a1d9eb0SPeter Maydell         gen_helper_neon_mull_s16,
21853a1d9eb0SPeter Maydell         gen_mull_s32,
21863a1d9eb0SPeter Maydell         NULL,
21873a1d9eb0SPeter Maydell     };
21883a1d9eb0SPeter Maydell 
21893a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
21903a1d9eb0SPeter Maydell }
21913a1d9eb0SPeter Maydell 
21923a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
21933a1d9eb0SPeter Maydell {
21943a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
21953a1d9eb0SPeter Maydell         gen_helper_neon_mull_u8,
21963a1d9eb0SPeter Maydell         gen_helper_neon_mull_u16,
21973a1d9eb0SPeter Maydell         gen_mull_u32,
21983a1d9eb0SPeter Maydell         NULL,
21993a1d9eb0SPeter Maydell     };
22003a1d9eb0SPeter Maydell 
22013a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
22023a1d9eb0SPeter Maydell }
22033a1d9eb0SPeter Maydell 
22043a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC)                                         \
22053a1d9eb0SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
22063a1d9eb0SPeter Maydell     {                                                                   \
22073a1d9eb0SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
22083a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##8,                                  \
22093a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
22103a1d9eb0SPeter Maydell             gen_##MULL##32,                                             \
22113a1d9eb0SPeter Maydell             NULL,                                                       \
22123a1d9eb0SPeter Maydell         };                                                              \
22133a1d9eb0SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
22143a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u16,                               \
22153a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
22163a1d9eb0SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
22173a1d9eb0SPeter Maydell             NULL,                                                       \
22183a1d9eb0SPeter Maydell         };                                                              \
22193a1d9eb0SPeter Maydell         return do_long_3d(s, a, opfn[a->size], accfn[a->size]);         \
22203a1d9eb0SPeter Maydell     }
22213a1d9eb0SPeter Maydell 
22223a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add)
22233a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add)
22243a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub)
22253a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub)
22269546ca59SPeter Maydell 
22279546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
22289546ca59SPeter Maydell {
22299546ca59SPeter Maydell     gen_helper_neon_mull_s16(rd, rn, rm);
22309546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd);
22319546ca59SPeter Maydell }
22329546ca59SPeter Maydell 
22339546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
22349546ca59SPeter Maydell {
22359546ca59SPeter Maydell     gen_mull_s32(rd, rn, rm);
22369546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd);
22379546ca59SPeter Maydell }
22389546ca59SPeter Maydell 
22399546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a)
22409546ca59SPeter Maydell {
22419546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22429546ca59SPeter Maydell         NULL,
22439546ca59SPeter Maydell         gen_VQDMULL_16,
22449546ca59SPeter Maydell         gen_VQDMULL_32,
22459546ca59SPeter Maydell         NULL,
22469546ca59SPeter Maydell     };
22479546ca59SPeter Maydell 
22489546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
22499546ca59SPeter Maydell }
22509546ca59SPeter Maydell 
22519546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22529546ca59SPeter Maydell {
22539546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
22549546ca59SPeter Maydell }
22559546ca59SPeter Maydell 
22569546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22579546ca59SPeter Maydell {
22589546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
22599546ca59SPeter Maydell }
22609546ca59SPeter Maydell 
22619546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a)
22629546ca59SPeter Maydell {
22639546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22649546ca59SPeter Maydell         NULL,
22659546ca59SPeter Maydell         gen_VQDMULL_16,
22669546ca59SPeter Maydell         gen_VQDMULL_32,
22679546ca59SPeter Maydell         NULL,
22689546ca59SPeter Maydell     };
22699546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
22709546ca59SPeter Maydell         NULL,
22719546ca59SPeter Maydell         gen_VQDMLAL_acc_16,
22729546ca59SPeter Maydell         gen_VQDMLAL_acc_32,
22739546ca59SPeter Maydell         NULL,
22749546ca59SPeter Maydell     };
22759546ca59SPeter Maydell 
22769546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
22779546ca59SPeter Maydell }
22789546ca59SPeter Maydell 
22799546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22809546ca59SPeter Maydell {
22819546ca59SPeter Maydell     gen_helper_neon_negl_u32(rm, rm);
22829546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
22839546ca59SPeter Maydell }
22849546ca59SPeter Maydell 
22859546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22869546ca59SPeter Maydell {
22879546ca59SPeter Maydell     tcg_gen_neg_i64(rm, rm);
22889546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
22899546ca59SPeter Maydell }
22909546ca59SPeter Maydell 
22919546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a)
22929546ca59SPeter Maydell {
22939546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22949546ca59SPeter Maydell         NULL,
22959546ca59SPeter Maydell         gen_VQDMULL_16,
22969546ca59SPeter Maydell         gen_VQDMULL_32,
22979546ca59SPeter Maydell         NULL,
22989546ca59SPeter Maydell     };
22999546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
23009546ca59SPeter Maydell         NULL,
23019546ca59SPeter Maydell         gen_VQDMLSL_acc_16,
23029546ca59SPeter Maydell         gen_VQDMLSL_acc_32,
23039546ca59SPeter Maydell         NULL,
23049546ca59SPeter Maydell     };
23059546ca59SPeter Maydell 
23069546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
23079546ca59SPeter Maydell }
230818fb58d5SPeter Maydell 
230918fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
231018fb58d5SPeter Maydell {
231118fb58d5SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
231218fb58d5SPeter Maydell 
231318fb58d5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
231418fb58d5SPeter Maydell         return false;
231518fb58d5SPeter Maydell     }
231618fb58d5SPeter Maydell 
231718fb58d5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
231818fb58d5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
231918fb58d5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
232018fb58d5SPeter Maydell         return false;
232118fb58d5SPeter Maydell     }
232218fb58d5SPeter Maydell 
232318fb58d5SPeter Maydell     if (a->vd & 1) {
232418fb58d5SPeter Maydell         return false;
232518fb58d5SPeter Maydell     }
232618fb58d5SPeter Maydell 
232718fb58d5SPeter Maydell     switch (a->size) {
232818fb58d5SPeter Maydell     case 0:
232918fb58d5SPeter Maydell         fn_gvec = gen_helper_neon_pmull_h;
233018fb58d5SPeter Maydell         break;
233118fb58d5SPeter Maydell     case 2:
233218fb58d5SPeter Maydell         if (!dc_isar_feature(aa32_pmull, s)) {
233318fb58d5SPeter Maydell             return false;
233418fb58d5SPeter Maydell         }
233518fb58d5SPeter Maydell         fn_gvec = gen_helper_gvec_pmull_q;
233618fb58d5SPeter Maydell         break;
233718fb58d5SPeter Maydell     default:
233818fb58d5SPeter Maydell         return false;
233918fb58d5SPeter Maydell     }
234018fb58d5SPeter Maydell 
234118fb58d5SPeter Maydell     if (!vfp_access_check(s)) {
234218fb58d5SPeter Maydell         return true;
234318fb58d5SPeter Maydell     }
234418fb58d5SPeter Maydell 
234518fb58d5SPeter Maydell     tcg_gen_gvec_3_ool(neon_reg_offset(a->vd, 0),
234618fb58d5SPeter Maydell                        neon_reg_offset(a->vn, 0),
234718fb58d5SPeter Maydell                        neon_reg_offset(a->vm, 0),
234818fb58d5SPeter Maydell                        16, 16, 0, fn_gvec);
234918fb58d5SPeter Maydell     return true;
235018fb58d5SPeter Maydell }
235196fc80f5SPeter Maydell 
235296fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var)
235396fc80f5SPeter Maydell {
235496fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
235596fc80f5SPeter Maydell     tcg_gen_ext16u_i32(var, var);
235696fc80f5SPeter Maydell     tcg_gen_shli_i32(tmp, var, 16);
235796fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
235896fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
235996fc80f5SPeter Maydell }
236096fc80f5SPeter Maydell 
236196fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var)
236296fc80f5SPeter Maydell {
236396fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
236496fc80f5SPeter Maydell     tcg_gen_andi_i32(var, var, 0xffff0000);
236596fc80f5SPeter Maydell     tcg_gen_shri_i32(tmp, var, 16);
236696fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
236796fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
236896fc80f5SPeter Maydell }
236996fc80f5SPeter Maydell 
237096fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg)
237196fc80f5SPeter Maydell {
237296fc80f5SPeter Maydell     TCGv_i32 tmp;
237396fc80f5SPeter Maydell     if (size == 1) {
237496fc80f5SPeter Maydell         tmp = neon_load_reg(reg & 7, reg >> 4);
237596fc80f5SPeter Maydell         if (reg & 8) {
237696fc80f5SPeter Maydell             gen_neon_dup_high16(tmp);
237796fc80f5SPeter Maydell         } else {
237896fc80f5SPeter Maydell             gen_neon_dup_low16(tmp);
237996fc80f5SPeter Maydell         }
238096fc80f5SPeter Maydell     } else {
238196fc80f5SPeter Maydell         tmp = neon_load_reg(reg & 15, reg >> 4);
238296fc80f5SPeter Maydell     }
238396fc80f5SPeter Maydell     return tmp;
238496fc80f5SPeter Maydell }
238596fc80f5SPeter Maydell 
238696fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a,
238796fc80f5SPeter Maydell                        NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn)
238896fc80f5SPeter Maydell {
238996fc80f5SPeter Maydell     /*
239096fc80f5SPeter Maydell      * Two registers and a scalar: perform an operation between
239196fc80f5SPeter Maydell      * the input elements and the scalar, and then possibly
239296fc80f5SPeter Maydell      * perform an accumulation operation of that result into the
239396fc80f5SPeter Maydell      * destination.
239496fc80f5SPeter Maydell      */
239596fc80f5SPeter Maydell     TCGv_i32 scalar;
239696fc80f5SPeter Maydell     int pass;
239796fc80f5SPeter Maydell 
239896fc80f5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
239996fc80f5SPeter Maydell         return false;
240096fc80f5SPeter Maydell     }
240196fc80f5SPeter Maydell 
240296fc80f5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
240396fc80f5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
240496fc80f5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
240596fc80f5SPeter Maydell         return false;
240696fc80f5SPeter Maydell     }
240796fc80f5SPeter Maydell 
240896fc80f5SPeter Maydell     if (!opfn) {
240996fc80f5SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
241096fc80f5SPeter Maydell         return false;
241196fc80f5SPeter Maydell     }
241296fc80f5SPeter Maydell 
241396fc80f5SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
241496fc80f5SPeter Maydell         return false;
241596fc80f5SPeter Maydell     }
241696fc80f5SPeter Maydell 
241796fc80f5SPeter Maydell     if (!vfp_access_check(s)) {
241896fc80f5SPeter Maydell         return true;
241996fc80f5SPeter Maydell     }
242096fc80f5SPeter Maydell 
242196fc80f5SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
242296fc80f5SPeter Maydell 
242396fc80f5SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
242496fc80f5SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, pass);
242596fc80f5SPeter Maydell         opfn(tmp, tmp, scalar);
242696fc80f5SPeter Maydell         if (accfn) {
242796fc80f5SPeter Maydell             TCGv_i32 rd = neon_load_reg(a->vd, pass);
242896fc80f5SPeter Maydell             accfn(tmp, rd, tmp);
242996fc80f5SPeter Maydell             tcg_temp_free_i32(rd);
243096fc80f5SPeter Maydell         }
243196fc80f5SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
243296fc80f5SPeter Maydell     }
243396fc80f5SPeter Maydell     tcg_temp_free_i32(scalar);
243496fc80f5SPeter Maydell     return true;
243596fc80f5SPeter Maydell }
243696fc80f5SPeter Maydell 
243796fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a)
243896fc80f5SPeter Maydell {
243996fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
244096fc80f5SPeter Maydell         NULL,
244196fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
244296fc80f5SPeter Maydell         tcg_gen_mul_i32,
244396fc80f5SPeter Maydell         NULL,
244496fc80f5SPeter Maydell     };
244596fc80f5SPeter Maydell 
244696fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
244796fc80f5SPeter Maydell }
244896fc80f5SPeter Maydell 
244996fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a)
245096fc80f5SPeter Maydell {
245196fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
245296fc80f5SPeter Maydell         NULL,
245396fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
245496fc80f5SPeter Maydell         tcg_gen_mul_i32,
245596fc80f5SPeter Maydell         NULL,
245696fc80f5SPeter Maydell     };
245796fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
245896fc80f5SPeter Maydell         NULL,
245996fc80f5SPeter Maydell         gen_helper_neon_add_u16,
246096fc80f5SPeter Maydell         tcg_gen_add_i32,
246196fc80f5SPeter Maydell         NULL,
246296fc80f5SPeter Maydell     };
246396fc80f5SPeter Maydell 
246496fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
246596fc80f5SPeter Maydell }
246696fc80f5SPeter Maydell 
246796fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a)
246896fc80f5SPeter Maydell {
246996fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
247096fc80f5SPeter Maydell         NULL,
247196fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
247296fc80f5SPeter Maydell         tcg_gen_mul_i32,
247396fc80f5SPeter Maydell         NULL,
247496fc80f5SPeter Maydell     };
247596fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
247696fc80f5SPeter Maydell         NULL,
247796fc80f5SPeter Maydell         gen_helper_neon_sub_u16,
247896fc80f5SPeter Maydell         tcg_gen_sub_i32,
247996fc80f5SPeter Maydell         NULL,
248096fc80f5SPeter Maydell     };
248196fc80f5SPeter Maydell 
248296fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
248396fc80f5SPeter Maydell }
248485ac9aefSPeter Maydell 
248585ac9aefSPeter Maydell /*
248685ac9aefSPeter Maydell  * Rather than have a float-specific version of do_2scalar just for
248785ac9aefSPeter Maydell  * three insns, we wrap a NeonGenTwoSingleOpFn to turn it into
248885ac9aefSPeter Maydell  * a NeonGenTwoOpFn.
248985ac9aefSPeter Maydell  */
249085ac9aefSPeter Maydell #define WRAP_FP_FN(WRAPNAME, FUNC)                              \
249185ac9aefSPeter Maydell     static void WRAPNAME(TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \
249285ac9aefSPeter Maydell     {                                                           \
249385ac9aefSPeter Maydell         TCGv_ptr fpstatus = get_fpstatus_ptr(1);                \
249485ac9aefSPeter Maydell         FUNC(rd, rn, rm, fpstatus);                             \
249585ac9aefSPeter Maydell         tcg_temp_free_ptr(fpstatus);                            \
249685ac9aefSPeter Maydell     }
249785ac9aefSPeter Maydell 
249885ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls)
249985ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds)
250085ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs)
250185ac9aefSPeter Maydell 
250285ac9aefSPeter Maydell static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a)
250385ac9aefSPeter Maydell {
250485ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
250585ac9aefSPeter Maydell         NULL,
250685ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
250785ac9aefSPeter Maydell         gen_VMUL_F_mul,
250885ac9aefSPeter Maydell         NULL,
250985ac9aefSPeter Maydell     };
251085ac9aefSPeter Maydell 
251185ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
251285ac9aefSPeter Maydell }
251385ac9aefSPeter Maydell 
251485ac9aefSPeter Maydell static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a)
251585ac9aefSPeter Maydell {
251685ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
251785ac9aefSPeter Maydell         NULL,
251885ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
251985ac9aefSPeter Maydell         gen_VMUL_F_mul,
252085ac9aefSPeter Maydell         NULL,
252185ac9aefSPeter Maydell     };
252285ac9aefSPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
252385ac9aefSPeter Maydell         NULL,
252485ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
252585ac9aefSPeter Maydell         gen_VMUL_F_add,
252685ac9aefSPeter Maydell         NULL,
252785ac9aefSPeter Maydell     };
252885ac9aefSPeter Maydell 
252985ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
253085ac9aefSPeter Maydell }
253185ac9aefSPeter Maydell 
253285ac9aefSPeter Maydell static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a)
253385ac9aefSPeter Maydell {
253485ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
253585ac9aefSPeter Maydell         NULL,
253685ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
253785ac9aefSPeter Maydell         gen_VMUL_F_mul,
253885ac9aefSPeter Maydell         NULL,
253985ac9aefSPeter Maydell     };
254085ac9aefSPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
254185ac9aefSPeter Maydell         NULL,
254285ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
254385ac9aefSPeter Maydell         gen_VMUL_F_sub,
254485ac9aefSPeter Maydell         NULL,
254585ac9aefSPeter Maydell     };
254685ac9aefSPeter Maydell 
254785ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
254885ac9aefSPeter Maydell }
2549b2fc7be9SPeter Maydell 
2550b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
2551b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
2552b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16)
2553b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32)
2554b2fc7be9SPeter Maydell 
2555b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a)
2556b2fc7be9SPeter Maydell {
2557b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2558b2fc7be9SPeter Maydell         NULL,
2559b2fc7be9SPeter Maydell         gen_VQDMULH_16,
2560b2fc7be9SPeter Maydell         gen_VQDMULH_32,
2561b2fc7be9SPeter Maydell         NULL,
2562b2fc7be9SPeter Maydell     };
2563b2fc7be9SPeter Maydell 
2564b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2565b2fc7be9SPeter Maydell }
2566b2fc7be9SPeter Maydell 
2567b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a)
2568b2fc7be9SPeter Maydell {
2569b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2570b2fc7be9SPeter Maydell         NULL,
2571b2fc7be9SPeter Maydell         gen_VQRDMULH_16,
2572b2fc7be9SPeter Maydell         gen_VQRDMULH_32,
2573b2fc7be9SPeter Maydell         NULL,
2574b2fc7be9SPeter Maydell     };
2575b2fc7be9SPeter Maydell 
2576b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2577b2fc7be9SPeter Maydell }
2578aa318f5bSPeter Maydell 
2579aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a,
2580aa318f5bSPeter Maydell                             NeonGenThreeOpEnvFn *opfn)
2581aa318f5bSPeter Maydell {
2582aa318f5bSPeter Maydell     /*
2583aa318f5bSPeter Maydell      * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn
2584aa318f5bSPeter Maydell      * performs a kind of fused op-then-accumulate using a helper
2585aa318f5bSPeter Maydell      * function that takes all of rd, rn and the scalar at once.
2586aa318f5bSPeter Maydell      */
2587aa318f5bSPeter Maydell     TCGv_i32 scalar;
2588aa318f5bSPeter Maydell     int pass;
2589aa318f5bSPeter Maydell 
2590aa318f5bSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2591aa318f5bSPeter Maydell         return false;
2592aa318f5bSPeter Maydell     }
2593aa318f5bSPeter Maydell 
2594aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_rdm, s)) {
2595aa318f5bSPeter Maydell         return false;
2596aa318f5bSPeter Maydell     }
2597aa318f5bSPeter Maydell 
2598aa318f5bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2599aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2600aa318f5bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2601aa318f5bSPeter Maydell         return false;
2602aa318f5bSPeter Maydell     }
2603aa318f5bSPeter Maydell 
2604aa318f5bSPeter Maydell     if (!opfn) {
2605aa318f5bSPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2606aa318f5bSPeter Maydell         return false;
2607aa318f5bSPeter Maydell     }
2608aa318f5bSPeter Maydell 
2609aa318f5bSPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2610aa318f5bSPeter Maydell         return false;
2611aa318f5bSPeter Maydell     }
2612aa318f5bSPeter Maydell 
2613aa318f5bSPeter Maydell     if (!vfp_access_check(s)) {
2614aa318f5bSPeter Maydell         return true;
2615aa318f5bSPeter Maydell     }
2616aa318f5bSPeter Maydell 
2617aa318f5bSPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2618aa318f5bSPeter Maydell 
2619aa318f5bSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2620aa318f5bSPeter Maydell         TCGv_i32 rn = neon_load_reg(a->vn, pass);
2621aa318f5bSPeter Maydell         TCGv_i32 rd = neon_load_reg(a->vd, pass);
2622aa318f5bSPeter Maydell         opfn(rd, cpu_env, rn, scalar, rd);
2623aa318f5bSPeter Maydell         tcg_temp_free_i32(rn);
2624aa318f5bSPeter Maydell         neon_store_reg(a->vd, pass, rd);
2625aa318f5bSPeter Maydell     }
2626aa318f5bSPeter Maydell     tcg_temp_free_i32(scalar);
2627aa318f5bSPeter Maydell 
2628aa318f5bSPeter Maydell     return true;
2629aa318f5bSPeter Maydell }
2630aa318f5bSPeter Maydell 
2631aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a)
2632aa318f5bSPeter Maydell {
2633aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2634aa318f5bSPeter Maydell         NULL,
2635aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s16,
2636aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s32,
2637aa318f5bSPeter Maydell         NULL,
2638aa318f5bSPeter Maydell     };
2639aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2640aa318f5bSPeter Maydell }
2641aa318f5bSPeter Maydell 
2642aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a)
2643aa318f5bSPeter Maydell {
2644aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2645aa318f5bSPeter Maydell         NULL,
2646aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s16,
2647aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s32,
2648aa318f5bSPeter Maydell         NULL,
2649aa318f5bSPeter Maydell     };
2650aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2651aa318f5bSPeter Maydell }
265277e576a9SPeter Maydell 
265377e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a,
265477e576a9SPeter Maydell                             NeonGenTwoOpWidenFn *opfn,
265577e576a9SPeter Maydell                             NeonGenTwo64OpFn *accfn)
265677e576a9SPeter Maydell {
265777e576a9SPeter Maydell     /*
265877e576a9SPeter Maydell      * Two registers and a scalar, long operations: perform an
265977e576a9SPeter Maydell      * operation on the input elements and the scalar which produces
266077e576a9SPeter Maydell      * a double-width result, and then possibly perform an accumulation
266177e576a9SPeter Maydell      * operation of that result into the destination.
266277e576a9SPeter Maydell      */
266377e576a9SPeter Maydell     TCGv_i32 scalar, rn;
266477e576a9SPeter Maydell     TCGv_i64 rn0_64, rn1_64;
266577e576a9SPeter Maydell 
266677e576a9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
266777e576a9SPeter Maydell         return false;
266877e576a9SPeter Maydell     }
266977e576a9SPeter Maydell 
267077e576a9SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
267177e576a9SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
267277e576a9SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
267377e576a9SPeter Maydell         return false;
267477e576a9SPeter Maydell     }
267577e576a9SPeter Maydell 
267677e576a9SPeter Maydell     if (!opfn) {
267777e576a9SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
267877e576a9SPeter Maydell         return false;
267977e576a9SPeter Maydell     }
268077e576a9SPeter Maydell 
268177e576a9SPeter Maydell     if (a->vd & 1) {
268277e576a9SPeter Maydell         return false;
268377e576a9SPeter Maydell     }
268477e576a9SPeter Maydell 
268577e576a9SPeter Maydell     if (!vfp_access_check(s)) {
268677e576a9SPeter Maydell         return true;
268777e576a9SPeter Maydell     }
268877e576a9SPeter Maydell 
268977e576a9SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
269077e576a9SPeter Maydell 
269177e576a9SPeter Maydell     /* Load all inputs before writing any outputs, in case of overlap */
269277e576a9SPeter Maydell     rn = neon_load_reg(a->vn, 0);
269377e576a9SPeter Maydell     rn0_64 = tcg_temp_new_i64();
269477e576a9SPeter Maydell     opfn(rn0_64, rn, scalar);
269577e576a9SPeter Maydell     tcg_temp_free_i32(rn);
269677e576a9SPeter Maydell 
269777e576a9SPeter Maydell     rn = neon_load_reg(a->vn, 1);
269877e576a9SPeter Maydell     rn1_64 = tcg_temp_new_i64();
269977e576a9SPeter Maydell     opfn(rn1_64, rn, scalar);
270077e576a9SPeter Maydell     tcg_temp_free_i32(rn);
270177e576a9SPeter Maydell     tcg_temp_free_i32(scalar);
270277e576a9SPeter Maydell 
270377e576a9SPeter Maydell     if (accfn) {
270477e576a9SPeter Maydell         TCGv_i64 t64 = tcg_temp_new_i64();
270577e576a9SPeter Maydell         neon_load_reg64(t64, a->vd);
270677e576a9SPeter Maydell         accfn(t64, t64, rn0_64);
270777e576a9SPeter Maydell         neon_store_reg64(t64, a->vd);
270877e576a9SPeter Maydell         neon_load_reg64(t64, a->vd + 1);
270977e576a9SPeter Maydell         accfn(t64, t64, rn1_64);
271077e576a9SPeter Maydell         neon_store_reg64(t64, a->vd + 1);
271177e576a9SPeter Maydell         tcg_temp_free_i64(t64);
271277e576a9SPeter Maydell     } else {
271377e576a9SPeter Maydell         neon_store_reg64(rn0_64, a->vd);
271477e576a9SPeter Maydell         neon_store_reg64(rn1_64, a->vd + 1);
271577e576a9SPeter Maydell     }
271677e576a9SPeter Maydell     tcg_temp_free_i64(rn0_64);
271777e576a9SPeter Maydell     tcg_temp_free_i64(rn1_64);
271877e576a9SPeter Maydell     return true;
271977e576a9SPeter Maydell }
272077e576a9SPeter Maydell 
272177e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a)
272277e576a9SPeter Maydell {
272377e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
272477e576a9SPeter Maydell         NULL,
272577e576a9SPeter Maydell         gen_helper_neon_mull_s16,
272677e576a9SPeter Maydell         gen_mull_s32,
272777e576a9SPeter Maydell         NULL,
272877e576a9SPeter Maydell     };
272977e576a9SPeter Maydell 
273077e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
273177e576a9SPeter Maydell }
273277e576a9SPeter Maydell 
273377e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a)
273477e576a9SPeter Maydell {
273577e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
273677e576a9SPeter Maydell         NULL,
273777e576a9SPeter Maydell         gen_helper_neon_mull_u16,
273877e576a9SPeter Maydell         gen_mull_u32,
273977e576a9SPeter Maydell         NULL,
274077e576a9SPeter Maydell     };
274177e576a9SPeter Maydell 
274277e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
274377e576a9SPeter Maydell }
274477e576a9SPeter Maydell 
274577e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC)                                   \
274677e576a9SPeter Maydell     static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a)     \
274777e576a9SPeter Maydell     {                                                                   \
274877e576a9SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
274977e576a9SPeter Maydell             NULL,                                                       \
275077e576a9SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
275177e576a9SPeter Maydell             gen_##MULL##32,                                             \
275277e576a9SPeter Maydell             NULL,                                                       \
275377e576a9SPeter Maydell         };                                                              \
275477e576a9SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
275577e576a9SPeter Maydell             NULL,                                                       \
275677e576a9SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
275777e576a9SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
275877e576a9SPeter Maydell             NULL,                                                       \
275977e576a9SPeter Maydell         };                                                              \
276077e576a9SPeter Maydell         return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);    \
276177e576a9SPeter Maydell     }
276277e576a9SPeter Maydell 
276377e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add)
276477e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add)
276577e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub)
276677e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub)
276777e576a9SPeter Maydell 
276877e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a)
276977e576a9SPeter Maydell {
277077e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
277177e576a9SPeter Maydell         NULL,
277277e576a9SPeter Maydell         gen_VQDMULL_16,
277377e576a9SPeter Maydell         gen_VQDMULL_32,
277477e576a9SPeter Maydell         NULL,
277577e576a9SPeter Maydell     };
277677e576a9SPeter Maydell 
277777e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
277877e576a9SPeter Maydell }
277977e576a9SPeter Maydell 
278077e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a)
278177e576a9SPeter Maydell {
278277e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
278377e576a9SPeter Maydell         NULL,
278477e576a9SPeter Maydell         gen_VQDMULL_16,
278577e576a9SPeter Maydell         gen_VQDMULL_32,
278677e576a9SPeter Maydell         NULL,
278777e576a9SPeter Maydell     };
278877e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
278977e576a9SPeter Maydell         NULL,
279077e576a9SPeter Maydell         gen_VQDMLAL_acc_16,
279177e576a9SPeter Maydell         gen_VQDMLAL_acc_32,
279277e576a9SPeter Maydell         NULL,
279377e576a9SPeter Maydell     };
279477e576a9SPeter Maydell 
279577e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
279677e576a9SPeter Maydell }
279777e576a9SPeter Maydell 
279877e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a)
279977e576a9SPeter Maydell {
280077e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
280177e576a9SPeter Maydell         NULL,
280277e576a9SPeter Maydell         gen_VQDMULL_16,
280377e576a9SPeter Maydell         gen_VQDMULL_32,
280477e576a9SPeter Maydell         NULL,
280577e576a9SPeter Maydell     };
280677e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
280777e576a9SPeter Maydell         NULL,
280877e576a9SPeter Maydell         gen_VQDMLSL_acc_16,
280977e576a9SPeter Maydell         gen_VQDMLSL_acc_32,
281077e576a9SPeter Maydell         NULL,
281177e576a9SPeter Maydell     };
281277e576a9SPeter Maydell 
281377e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
281477e576a9SPeter Maydell }
28150aad761fSPeter Maydell 
28160aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
28170aad761fSPeter Maydell {
28180aad761fSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
28190aad761fSPeter Maydell         return false;
28200aad761fSPeter Maydell     }
28210aad761fSPeter Maydell 
28220aad761fSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
28230aad761fSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
28240aad761fSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
28250aad761fSPeter Maydell         return false;
28260aad761fSPeter Maydell     }
28270aad761fSPeter Maydell 
28280aad761fSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
28290aad761fSPeter Maydell         return false;
28300aad761fSPeter Maydell     }
28310aad761fSPeter Maydell 
28320aad761fSPeter Maydell     if (a->imm > 7 && !a->q) {
28330aad761fSPeter Maydell         return false;
28340aad761fSPeter Maydell     }
28350aad761fSPeter Maydell 
28360aad761fSPeter Maydell     if (!vfp_access_check(s)) {
28370aad761fSPeter Maydell         return true;
28380aad761fSPeter Maydell     }
28390aad761fSPeter Maydell 
28400aad761fSPeter Maydell     if (!a->q) {
28410aad761fSPeter Maydell         /* Extract 64 bits from <Vm:Vn> */
28420aad761fSPeter Maydell         TCGv_i64 left, right, dest;
28430aad761fSPeter Maydell 
28440aad761fSPeter Maydell         left = tcg_temp_new_i64();
28450aad761fSPeter Maydell         right = tcg_temp_new_i64();
28460aad761fSPeter Maydell         dest = tcg_temp_new_i64();
28470aad761fSPeter Maydell 
28480aad761fSPeter Maydell         neon_load_reg64(right, a->vn);
28490aad761fSPeter Maydell         neon_load_reg64(left, a->vm);
28500aad761fSPeter Maydell         tcg_gen_extract2_i64(dest, right, left, a->imm * 8);
28510aad761fSPeter Maydell         neon_store_reg64(dest, a->vd);
28520aad761fSPeter Maydell 
28530aad761fSPeter Maydell         tcg_temp_free_i64(left);
28540aad761fSPeter Maydell         tcg_temp_free_i64(right);
28550aad761fSPeter Maydell         tcg_temp_free_i64(dest);
28560aad761fSPeter Maydell     } else {
28570aad761fSPeter Maydell         /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */
28580aad761fSPeter Maydell         TCGv_i64 left, middle, right, destleft, destright;
28590aad761fSPeter Maydell 
28600aad761fSPeter Maydell         left = tcg_temp_new_i64();
28610aad761fSPeter Maydell         middle = tcg_temp_new_i64();
28620aad761fSPeter Maydell         right = tcg_temp_new_i64();
28630aad761fSPeter Maydell         destleft = tcg_temp_new_i64();
28640aad761fSPeter Maydell         destright = tcg_temp_new_i64();
28650aad761fSPeter Maydell 
28660aad761fSPeter Maydell         if (a->imm < 8) {
28670aad761fSPeter Maydell             neon_load_reg64(right, a->vn);
28680aad761fSPeter Maydell             neon_load_reg64(middle, a->vn + 1);
28690aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, a->imm * 8);
28700aad761fSPeter Maydell             neon_load_reg64(left, a->vm);
28710aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8);
28720aad761fSPeter Maydell         } else {
28730aad761fSPeter Maydell             neon_load_reg64(right, a->vn + 1);
28740aad761fSPeter Maydell             neon_load_reg64(middle, a->vm);
28750aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8);
28760aad761fSPeter Maydell             neon_load_reg64(left, a->vm + 1);
28770aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8);
28780aad761fSPeter Maydell         }
28790aad761fSPeter Maydell 
28800aad761fSPeter Maydell         neon_store_reg64(destright, a->vd);
28810aad761fSPeter Maydell         neon_store_reg64(destleft, a->vd + 1);
28820aad761fSPeter Maydell 
28830aad761fSPeter Maydell         tcg_temp_free_i64(destright);
28840aad761fSPeter Maydell         tcg_temp_free_i64(destleft);
28850aad761fSPeter Maydell         tcg_temp_free_i64(right);
28860aad761fSPeter Maydell         tcg_temp_free_i64(middle);
28870aad761fSPeter Maydell         tcg_temp_free_i64(left);
28880aad761fSPeter Maydell     }
28890aad761fSPeter Maydell     return true;
28900aad761fSPeter Maydell }
289154e96c74SPeter Maydell 
289254e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
289354e96c74SPeter Maydell {
289454e96c74SPeter Maydell     int n;
289554e96c74SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3, tmp4;
289654e96c74SPeter Maydell     TCGv_ptr ptr1;
289754e96c74SPeter Maydell 
289854e96c74SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
289954e96c74SPeter Maydell         return false;
290054e96c74SPeter Maydell     }
290154e96c74SPeter Maydell 
290254e96c74SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
290354e96c74SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
290454e96c74SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
290554e96c74SPeter Maydell         return false;
290654e96c74SPeter Maydell     }
290754e96c74SPeter Maydell 
290854e96c74SPeter Maydell     if (!vfp_access_check(s)) {
290954e96c74SPeter Maydell         return true;
291054e96c74SPeter Maydell     }
291154e96c74SPeter Maydell 
291254e96c74SPeter Maydell     n = a->len + 1;
291354e96c74SPeter Maydell     if ((a->vn + n) > 32) {
291454e96c74SPeter Maydell         /*
291554e96c74SPeter Maydell          * This is UNPREDICTABLE; we choose to UNDEF to avoid the
291654e96c74SPeter Maydell          * helper function running off the end of the register file.
291754e96c74SPeter Maydell          */
291854e96c74SPeter Maydell         return false;
291954e96c74SPeter Maydell     }
292054e96c74SPeter Maydell     n <<= 3;
292154e96c74SPeter Maydell     if (a->op) {
292254e96c74SPeter Maydell         tmp = neon_load_reg(a->vd, 0);
292354e96c74SPeter Maydell     } else {
292454e96c74SPeter Maydell         tmp = tcg_temp_new_i32();
292554e96c74SPeter Maydell         tcg_gen_movi_i32(tmp, 0);
292654e96c74SPeter Maydell     }
292754e96c74SPeter Maydell     tmp2 = neon_load_reg(a->vm, 0);
292854e96c74SPeter Maydell     ptr1 = vfp_reg_ptr(true, a->vn);
292954e96c74SPeter Maydell     tmp4 = tcg_const_i32(n);
293054e96c74SPeter Maydell     gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4);
293154e96c74SPeter Maydell     tcg_temp_free_i32(tmp);
293254e96c74SPeter Maydell     if (a->op) {
293354e96c74SPeter Maydell         tmp = neon_load_reg(a->vd, 1);
293454e96c74SPeter Maydell     } else {
293554e96c74SPeter Maydell         tmp = tcg_temp_new_i32();
293654e96c74SPeter Maydell         tcg_gen_movi_i32(tmp, 0);
293754e96c74SPeter Maydell     }
293854e96c74SPeter Maydell     tmp3 = neon_load_reg(a->vm, 1);
293954e96c74SPeter Maydell     gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4);
294054e96c74SPeter Maydell     tcg_temp_free_i32(tmp4);
294154e96c74SPeter Maydell     tcg_temp_free_ptr(ptr1);
294254e96c74SPeter Maydell     neon_store_reg(a->vd, 0, tmp2);
294354e96c74SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
294454e96c74SPeter Maydell     tcg_temp_free_i32(tmp);
294554e96c74SPeter Maydell     return true;
294654e96c74SPeter Maydell }
29479aaa23c2SPeter Maydell 
29489aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
29499aaa23c2SPeter Maydell {
29509aaa23c2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
29519aaa23c2SPeter Maydell         return false;
29529aaa23c2SPeter Maydell     }
29539aaa23c2SPeter Maydell 
29549aaa23c2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
29559aaa23c2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
29569aaa23c2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
29579aaa23c2SPeter Maydell         return false;
29589aaa23c2SPeter Maydell     }
29599aaa23c2SPeter Maydell 
29609aaa23c2SPeter Maydell     if (a->vd & a->q) {
29619aaa23c2SPeter Maydell         return false;
29629aaa23c2SPeter Maydell     }
29639aaa23c2SPeter Maydell 
29649aaa23c2SPeter Maydell     if (!vfp_access_check(s)) {
29659aaa23c2SPeter Maydell         return true;
29669aaa23c2SPeter Maydell     }
29679aaa23c2SPeter Maydell 
29689aaa23c2SPeter Maydell     tcg_gen_gvec_dup_mem(a->size, neon_reg_offset(a->vd, 0),
29699aaa23c2SPeter Maydell                          neon_element_offset(a->vm, a->index, a->size),
29709aaa23c2SPeter Maydell                          a->q ? 16 : 8, a->q ? 16 : 8);
29719aaa23c2SPeter Maydell     return true;
29729aaa23c2SPeter Maydell }
2973353d2b85SPeter Maydell 
2974353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
2975353d2b85SPeter Maydell {
2976353d2b85SPeter Maydell     int pass, half;
2977353d2b85SPeter Maydell 
2978353d2b85SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2979353d2b85SPeter Maydell         return false;
2980353d2b85SPeter Maydell     }
2981353d2b85SPeter Maydell 
2982353d2b85SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2983353d2b85SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2984353d2b85SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2985353d2b85SPeter Maydell         return false;
2986353d2b85SPeter Maydell     }
2987353d2b85SPeter Maydell 
2988353d2b85SPeter Maydell     if ((a->vd | a->vm) & a->q) {
2989353d2b85SPeter Maydell         return false;
2990353d2b85SPeter Maydell     }
2991353d2b85SPeter Maydell 
2992353d2b85SPeter Maydell     if (a->size == 3) {
2993353d2b85SPeter Maydell         return false;
2994353d2b85SPeter Maydell     }
2995353d2b85SPeter Maydell 
2996353d2b85SPeter Maydell     if (!vfp_access_check(s)) {
2997353d2b85SPeter Maydell         return true;
2998353d2b85SPeter Maydell     }
2999353d2b85SPeter Maydell 
3000353d2b85SPeter Maydell     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
3001353d2b85SPeter Maydell         TCGv_i32 tmp[2];
3002353d2b85SPeter Maydell 
3003353d2b85SPeter Maydell         for (half = 0; half < 2; half++) {
3004353d2b85SPeter Maydell             tmp[half] = neon_load_reg(a->vm, pass * 2 + half);
3005353d2b85SPeter Maydell             switch (a->size) {
3006353d2b85SPeter Maydell             case 0:
3007353d2b85SPeter Maydell                 tcg_gen_bswap32_i32(tmp[half], tmp[half]);
3008353d2b85SPeter Maydell                 break;
3009353d2b85SPeter Maydell             case 1:
3010353d2b85SPeter Maydell                 gen_swap_half(tmp[half]);
3011353d2b85SPeter Maydell                 break;
3012353d2b85SPeter Maydell             case 2:
3013353d2b85SPeter Maydell                 break;
3014353d2b85SPeter Maydell             default:
3015353d2b85SPeter Maydell                 g_assert_not_reached();
3016353d2b85SPeter Maydell             }
3017353d2b85SPeter Maydell         }
3018353d2b85SPeter Maydell         neon_store_reg(a->vd, pass * 2, tmp[1]);
3019353d2b85SPeter Maydell         neon_store_reg(a->vd, pass * 2 + 1, tmp[0]);
3020353d2b85SPeter Maydell     }
3021353d2b85SPeter Maydell     return true;
3022353d2b85SPeter Maydell }
30236106af3aSPeter Maydell 
30246106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a,
30256106af3aSPeter Maydell                               NeonGenWidenFn *widenfn,
30266106af3aSPeter Maydell                               NeonGenTwo64OpFn *opfn,
30276106af3aSPeter Maydell                               NeonGenTwo64OpFn *accfn)
30286106af3aSPeter Maydell {
30296106af3aSPeter Maydell     /*
30306106af3aSPeter Maydell      * Pairwise long operations: widen both halves of the pair,
30316106af3aSPeter Maydell      * combine the pairs with the opfn, and then possibly accumulate
30326106af3aSPeter Maydell      * into the destination with the accfn.
30336106af3aSPeter Maydell      */
30346106af3aSPeter Maydell     int pass;
30356106af3aSPeter Maydell 
30366106af3aSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
30376106af3aSPeter Maydell         return false;
30386106af3aSPeter Maydell     }
30396106af3aSPeter Maydell 
30406106af3aSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
30416106af3aSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
30426106af3aSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
30436106af3aSPeter Maydell         return false;
30446106af3aSPeter Maydell     }
30456106af3aSPeter Maydell 
30466106af3aSPeter Maydell     if ((a->vd | a->vm) & a->q) {
30476106af3aSPeter Maydell         return false;
30486106af3aSPeter Maydell     }
30496106af3aSPeter Maydell 
30506106af3aSPeter Maydell     if (!widenfn) {
30516106af3aSPeter Maydell         return false;
30526106af3aSPeter Maydell     }
30536106af3aSPeter Maydell 
30546106af3aSPeter Maydell     if (!vfp_access_check(s)) {
30556106af3aSPeter Maydell         return true;
30566106af3aSPeter Maydell     }
30576106af3aSPeter Maydell 
30586106af3aSPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
30596106af3aSPeter Maydell         TCGv_i32 tmp;
30606106af3aSPeter Maydell         TCGv_i64 rm0_64, rm1_64, rd_64;
30616106af3aSPeter Maydell 
30626106af3aSPeter Maydell         rm0_64 = tcg_temp_new_i64();
30636106af3aSPeter Maydell         rm1_64 = tcg_temp_new_i64();
30646106af3aSPeter Maydell         rd_64 = tcg_temp_new_i64();
30656106af3aSPeter Maydell         tmp = neon_load_reg(a->vm, pass * 2);
30666106af3aSPeter Maydell         widenfn(rm0_64, tmp);
30676106af3aSPeter Maydell         tcg_temp_free_i32(tmp);
30686106af3aSPeter Maydell         tmp = neon_load_reg(a->vm, pass * 2 + 1);
30696106af3aSPeter Maydell         widenfn(rm1_64, tmp);
30706106af3aSPeter Maydell         tcg_temp_free_i32(tmp);
30716106af3aSPeter Maydell         opfn(rd_64, rm0_64, rm1_64);
30726106af3aSPeter Maydell         tcg_temp_free_i64(rm0_64);
30736106af3aSPeter Maydell         tcg_temp_free_i64(rm1_64);
30746106af3aSPeter Maydell 
30756106af3aSPeter Maydell         if (accfn) {
30766106af3aSPeter Maydell             TCGv_i64 tmp64 = tcg_temp_new_i64();
30776106af3aSPeter Maydell             neon_load_reg64(tmp64, a->vd + pass);
30786106af3aSPeter Maydell             accfn(rd_64, tmp64, rd_64);
30796106af3aSPeter Maydell             tcg_temp_free_i64(tmp64);
30806106af3aSPeter Maydell         }
30816106af3aSPeter Maydell         neon_store_reg64(rd_64, a->vd + pass);
30826106af3aSPeter Maydell         tcg_temp_free_i64(rd_64);
30836106af3aSPeter Maydell     }
30846106af3aSPeter Maydell     return true;
30856106af3aSPeter Maydell }
30866106af3aSPeter Maydell 
30876106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a)
30886106af3aSPeter Maydell {
30896106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
30906106af3aSPeter Maydell         gen_helper_neon_widen_s8,
30916106af3aSPeter Maydell         gen_helper_neon_widen_s16,
30926106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
30936106af3aSPeter Maydell         NULL,
30946106af3aSPeter Maydell     };
30956106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
30966106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
30976106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
30986106af3aSPeter Maydell         tcg_gen_add_i64,
30996106af3aSPeter Maydell         NULL,
31006106af3aSPeter Maydell     };
31016106af3aSPeter Maydell 
31026106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
31036106af3aSPeter Maydell }
31046106af3aSPeter Maydell 
31056106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a)
31066106af3aSPeter Maydell {
31076106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
31086106af3aSPeter Maydell         gen_helper_neon_widen_u8,
31096106af3aSPeter Maydell         gen_helper_neon_widen_u16,
31106106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
31116106af3aSPeter Maydell         NULL,
31126106af3aSPeter Maydell     };
31136106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
31146106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
31156106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
31166106af3aSPeter Maydell         tcg_gen_add_i64,
31176106af3aSPeter Maydell         NULL,
31186106af3aSPeter Maydell     };
31196106af3aSPeter Maydell 
31206106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
31216106af3aSPeter Maydell }
31226106af3aSPeter Maydell 
31236106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a)
31246106af3aSPeter Maydell {
31256106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
31266106af3aSPeter Maydell         gen_helper_neon_widen_s8,
31276106af3aSPeter Maydell         gen_helper_neon_widen_s16,
31286106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
31296106af3aSPeter Maydell         NULL,
31306106af3aSPeter Maydell     };
31316106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
31326106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
31336106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
31346106af3aSPeter Maydell         tcg_gen_add_i64,
31356106af3aSPeter Maydell         NULL,
31366106af3aSPeter Maydell     };
31376106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
31386106af3aSPeter Maydell         gen_helper_neon_addl_u16,
31396106af3aSPeter Maydell         gen_helper_neon_addl_u32,
31406106af3aSPeter Maydell         tcg_gen_add_i64,
31416106af3aSPeter Maydell         NULL,
31426106af3aSPeter Maydell     };
31436106af3aSPeter Maydell 
31446106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
31456106af3aSPeter Maydell                              accfn[a->size]);
31466106af3aSPeter Maydell }
31476106af3aSPeter Maydell 
31486106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
31496106af3aSPeter Maydell {
31506106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
31516106af3aSPeter Maydell         gen_helper_neon_widen_u8,
31526106af3aSPeter Maydell         gen_helper_neon_widen_u16,
31536106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
31546106af3aSPeter Maydell         NULL,
31556106af3aSPeter Maydell     };
31566106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
31576106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
31586106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
31596106af3aSPeter Maydell         tcg_gen_add_i64,
31606106af3aSPeter Maydell         NULL,
31616106af3aSPeter Maydell     };
31626106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
31636106af3aSPeter Maydell         gen_helper_neon_addl_u16,
31646106af3aSPeter Maydell         gen_helper_neon_addl_u32,
31656106af3aSPeter Maydell         tcg_gen_add_i64,
31666106af3aSPeter Maydell         NULL,
31676106af3aSPeter Maydell     };
31686106af3aSPeter Maydell 
31696106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
31706106af3aSPeter Maydell                              accfn[a->size]);
31716106af3aSPeter Maydell }
3172567663a2SPeter Maydell 
3173567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr);
3174567663a2SPeter Maydell 
3175567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
3176567663a2SPeter Maydell                        ZipFn *fn)
3177567663a2SPeter Maydell {
3178567663a2SPeter Maydell     TCGv_ptr pd, pm;
3179567663a2SPeter Maydell 
3180567663a2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3181567663a2SPeter Maydell         return false;
3182567663a2SPeter Maydell     }
3183567663a2SPeter Maydell 
3184567663a2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3185567663a2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3186567663a2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3187567663a2SPeter Maydell         return false;
3188567663a2SPeter Maydell     }
3189567663a2SPeter Maydell 
3190567663a2SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3191567663a2SPeter Maydell         return false;
3192567663a2SPeter Maydell     }
3193567663a2SPeter Maydell 
3194567663a2SPeter Maydell     if (!fn) {
3195567663a2SPeter Maydell         /* Bad size or size/q combination */
3196567663a2SPeter Maydell         return false;
3197567663a2SPeter Maydell     }
3198567663a2SPeter Maydell 
3199567663a2SPeter Maydell     if (!vfp_access_check(s)) {
3200567663a2SPeter Maydell         return true;
3201567663a2SPeter Maydell     }
3202567663a2SPeter Maydell 
3203567663a2SPeter Maydell     pd = vfp_reg_ptr(true, a->vd);
3204567663a2SPeter Maydell     pm = vfp_reg_ptr(true, a->vm);
3205567663a2SPeter Maydell     fn(pd, pm);
3206567663a2SPeter Maydell     tcg_temp_free_ptr(pd);
3207567663a2SPeter Maydell     tcg_temp_free_ptr(pm);
3208567663a2SPeter Maydell     return true;
3209567663a2SPeter Maydell }
3210567663a2SPeter Maydell 
3211567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a)
3212567663a2SPeter Maydell {
3213567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3214567663a2SPeter Maydell         {
3215567663a2SPeter Maydell             gen_helper_neon_unzip8,
3216567663a2SPeter Maydell             gen_helper_neon_unzip16,
3217567663a2SPeter Maydell             NULL,
3218567663a2SPeter Maydell             NULL,
3219567663a2SPeter Maydell         }, {
3220567663a2SPeter Maydell             gen_helper_neon_qunzip8,
3221567663a2SPeter Maydell             gen_helper_neon_qunzip16,
3222567663a2SPeter Maydell             gen_helper_neon_qunzip32,
3223567663a2SPeter Maydell             NULL,
3224567663a2SPeter Maydell         }
3225567663a2SPeter Maydell     };
3226567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3227567663a2SPeter Maydell }
3228567663a2SPeter Maydell 
3229567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a)
3230567663a2SPeter Maydell {
3231567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3232567663a2SPeter Maydell         {
3233567663a2SPeter Maydell             gen_helper_neon_zip8,
3234567663a2SPeter Maydell             gen_helper_neon_zip16,
3235567663a2SPeter Maydell             NULL,
3236567663a2SPeter Maydell             NULL,
3237567663a2SPeter Maydell         }, {
3238567663a2SPeter Maydell             gen_helper_neon_qzip8,
3239567663a2SPeter Maydell             gen_helper_neon_qzip16,
3240567663a2SPeter Maydell             gen_helper_neon_qzip32,
3241567663a2SPeter Maydell             NULL,
3242567663a2SPeter Maydell         }
3243567663a2SPeter Maydell     };
3244567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3245567663a2SPeter Maydell }
32463882bdacSPeter Maydell 
32473882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a,
32483882bdacSPeter Maydell                      NeonGenNarrowEnvFn *narrowfn)
32493882bdacSPeter Maydell {
32503882bdacSPeter Maydell     TCGv_i64 rm;
32513882bdacSPeter Maydell     TCGv_i32 rd0, rd1;
32523882bdacSPeter Maydell 
32533882bdacSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
32543882bdacSPeter Maydell         return false;
32553882bdacSPeter Maydell     }
32563882bdacSPeter Maydell 
32573882bdacSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
32583882bdacSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
32593882bdacSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
32603882bdacSPeter Maydell         return false;
32613882bdacSPeter Maydell     }
32623882bdacSPeter Maydell 
32633882bdacSPeter Maydell     if (a->vm & 1) {
32643882bdacSPeter Maydell         return false;
32653882bdacSPeter Maydell     }
32663882bdacSPeter Maydell 
32673882bdacSPeter Maydell     if (!narrowfn) {
32683882bdacSPeter Maydell         return false;
32693882bdacSPeter Maydell     }
32703882bdacSPeter Maydell 
32713882bdacSPeter Maydell     if (!vfp_access_check(s)) {
32723882bdacSPeter Maydell         return true;
32733882bdacSPeter Maydell     }
32743882bdacSPeter Maydell 
32753882bdacSPeter Maydell     rm = tcg_temp_new_i64();
32763882bdacSPeter Maydell     rd0 = tcg_temp_new_i32();
32773882bdacSPeter Maydell     rd1 = tcg_temp_new_i32();
32783882bdacSPeter Maydell 
32793882bdacSPeter Maydell     neon_load_reg64(rm, a->vm);
32803882bdacSPeter Maydell     narrowfn(rd0, cpu_env, rm);
32813882bdacSPeter Maydell     neon_load_reg64(rm, a->vm + 1);
32823882bdacSPeter Maydell     narrowfn(rd1, cpu_env, rm);
32833882bdacSPeter Maydell     neon_store_reg(a->vd, 0, rd0);
32843882bdacSPeter Maydell     neon_store_reg(a->vd, 1, rd1);
32853882bdacSPeter Maydell     tcg_temp_free_i64(rm);
32863882bdacSPeter Maydell     return true;
32873882bdacSPeter Maydell }
32883882bdacSPeter Maydell 
32893882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC)                                    \
32903882bdacSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
32913882bdacSPeter Maydell     {                                                           \
32923882bdacSPeter Maydell         static NeonGenNarrowEnvFn * const narrowfn[] = {        \
32933882bdacSPeter Maydell             FUNC##8,                                            \
32943882bdacSPeter Maydell             FUNC##16,                                           \
32953882bdacSPeter Maydell             FUNC##32,                                           \
32963882bdacSPeter Maydell             NULL,                                               \
32973882bdacSPeter Maydell         };                                                      \
32983882bdacSPeter Maydell         return do_vmovn(s, a, narrowfn[a->size]);               \
32993882bdacSPeter Maydell     }
33003882bdacSPeter Maydell 
33013882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u)
33023882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
33033882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
33043882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
3305749e2be3SPeter Maydell 
3306749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
3307749e2be3SPeter Maydell {
3308749e2be3SPeter Maydell     TCGv_i32 rm0, rm1;
3309749e2be3SPeter Maydell     TCGv_i64 rd;
3310749e2be3SPeter Maydell     static NeonGenWidenFn * const widenfns[] = {
3311749e2be3SPeter Maydell         gen_helper_neon_widen_u8,
3312749e2be3SPeter Maydell         gen_helper_neon_widen_u16,
3313749e2be3SPeter Maydell         tcg_gen_extu_i32_i64,
3314749e2be3SPeter Maydell         NULL,
3315749e2be3SPeter Maydell     };
3316749e2be3SPeter Maydell     NeonGenWidenFn *widenfn = widenfns[a->size];
3317749e2be3SPeter Maydell 
3318749e2be3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3319749e2be3SPeter Maydell         return false;
3320749e2be3SPeter Maydell     }
3321749e2be3SPeter Maydell 
3322749e2be3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3323749e2be3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3324749e2be3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3325749e2be3SPeter Maydell         return false;
3326749e2be3SPeter Maydell     }
3327749e2be3SPeter Maydell 
3328749e2be3SPeter Maydell     if (a->vd & 1) {
3329749e2be3SPeter Maydell         return false;
3330749e2be3SPeter Maydell     }
3331749e2be3SPeter Maydell 
3332749e2be3SPeter Maydell     if (!widenfn) {
3333749e2be3SPeter Maydell         return false;
3334749e2be3SPeter Maydell     }
3335749e2be3SPeter Maydell 
3336749e2be3SPeter Maydell     if (!vfp_access_check(s)) {
3337749e2be3SPeter Maydell         return true;
3338749e2be3SPeter Maydell     }
3339749e2be3SPeter Maydell 
3340749e2be3SPeter Maydell     rd = tcg_temp_new_i64();
3341749e2be3SPeter Maydell 
3342749e2be3SPeter Maydell     rm0 = neon_load_reg(a->vm, 0);
3343749e2be3SPeter Maydell     rm1 = neon_load_reg(a->vm, 1);
3344749e2be3SPeter Maydell 
3345749e2be3SPeter Maydell     widenfn(rd, rm0);
3346749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
3347749e2be3SPeter Maydell     neon_store_reg64(rd, a->vd);
3348749e2be3SPeter Maydell     widenfn(rd, rm1);
3349749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
3350749e2be3SPeter Maydell     neon_store_reg64(rd, a->vd + 1);
3351749e2be3SPeter Maydell 
3352749e2be3SPeter Maydell     tcg_temp_free_i64(rd);
3353749e2be3SPeter Maydell     tcg_temp_free_i32(rm0);
3354749e2be3SPeter Maydell     tcg_temp_free_i32(rm1);
3355749e2be3SPeter Maydell     return true;
3356749e2be3SPeter Maydell }
3357654a5173SPeter Maydell 
3358654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
3359654a5173SPeter Maydell {
3360654a5173SPeter Maydell     TCGv_ptr fpst;
3361654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3362654a5173SPeter Maydell 
3363654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3364654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3365654a5173SPeter Maydell         return false;
3366654a5173SPeter Maydell     }
3367654a5173SPeter Maydell 
3368654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3369654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3370654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3371654a5173SPeter Maydell         return false;
3372654a5173SPeter Maydell     }
3373654a5173SPeter Maydell 
3374654a5173SPeter Maydell     if ((a->vm & 1) || (a->size != 1)) {
3375654a5173SPeter Maydell         return false;
3376654a5173SPeter Maydell     }
3377654a5173SPeter Maydell 
3378654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3379654a5173SPeter Maydell         return true;
3380654a5173SPeter Maydell     }
3381654a5173SPeter Maydell 
3382654a5173SPeter Maydell     fpst = get_fpstatus_ptr(true);
3383654a5173SPeter Maydell     ahp = get_ahp_flag();
3384654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 0);
3385654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3386654a5173SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
3387654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
3388654a5173SPeter Maydell     tcg_gen_shli_i32(tmp2, tmp2, 16);
3389654a5173SPeter Maydell     tcg_gen_or_i32(tmp2, tmp2, tmp);
3390654a5173SPeter Maydell     tcg_temp_free_i32(tmp);
3391654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 2);
3392654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3393654a5173SPeter Maydell     tmp3 = neon_load_reg(a->vm, 3);
3394654a5173SPeter Maydell     neon_store_reg(a->vd, 0, tmp2);
3395654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
3396654a5173SPeter Maydell     tcg_gen_shli_i32(tmp3, tmp3, 16);
3397654a5173SPeter Maydell     tcg_gen_or_i32(tmp3, tmp3, tmp);
3398654a5173SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
3399654a5173SPeter Maydell     tcg_temp_free_i32(tmp);
3400654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3401654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3402654a5173SPeter Maydell 
3403654a5173SPeter Maydell     return true;
3404654a5173SPeter Maydell }
3405654a5173SPeter Maydell 
3406654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
3407654a5173SPeter Maydell {
3408654a5173SPeter Maydell     TCGv_ptr fpst;
3409654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3410654a5173SPeter Maydell 
3411654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3412654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3413654a5173SPeter Maydell         return false;
3414654a5173SPeter Maydell     }
3415654a5173SPeter Maydell 
3416654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3417654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3418654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3419654a5173SPeter Maydell         return false;
3420654a5173SPeter Maydell     }
3421654a5173SPeter Maydell 
3422654a5173SPeter Maydell     if ((a->vd & 1) || (a->size != 1)) {
3423654a5173SPeter Maydell         return false;
3424654a5173SPeter Maydell     }
3425654a5173SPeter Maydell 
3426654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3427654a5173SPeter Maydell         return true;
3428654a5173SPeter Maydell     }
3429654a5173SPeter Maydell 
3430654a5173SPeter Maydell     fpst = get_fpstatus_ptr(true);
3431654a5173SPeter Maydell     ahp = get_ahp_flag();
3432654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
3433654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 0);
3434654a5173SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
3435654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp);
3436654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3437654a5173SPeter Maydell     neon_store_reg(a->vd, 0, tmp3);
3438654a5173SPeter Maydell     tcg_gen_shri_i32(tmp, tmp, 16);
3439654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
3440654a5173SPeter Maydell     neon_store_reg(a->vd, 1, tmp);
3441654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
3442654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp2);
3443654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3444654a5173SPeter Maydell     neon_store_reg(a->vd, 2, tmp3);
3445654a5173SPeter Maydell     tcg_gen_shri_i32(tmp2, tmp2, 16);
3446654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
3447654a5173SPeter Maydell     neon_store_reg(a->vd, 3, tmp2);
3448654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3449654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3450654a5173SPeter Maydell 
3451654a5173SPeter Maydell     return true;
3452654a5173SPeter Maydell }
345375153179SPeter Maydell 
345475153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
345575153179SPeter Maydell {
345675153179SPeter Maydell     int vec_size = a->q ? 16 : 8;
345775153179SPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
345875153179SPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
345975153179SPeter Maydell 
346075153179SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
346175153179SPeter Maydell         return false;
346275153179SPeter Maydell     }
346375153179SPeter Maydell 
346475153179SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
346575153179SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
346675153179SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
346775153179SPeter Maydell         return false;
346875153179SPeter Maydell     }
346975153179SPeter Maydell 
347075153179SPeter Maydell     if (a->size == 3) {
347175153179SPeter Maydell         return false;
347275153179SPeter Maydell     }
347375153179SPeter Maydell 
347475153179SPeter Maydell     if ((a->vd | a->vm) & a->q) {
347575153179SPeter Maydell         return false;
347675153179SPeter Maydell     }
347775153179SPeter Maydell 
347875153179SPeter Maydell     if (!vfp_access_check(s)) {
347975153179SPeter Maydell         return true;
348075153179SPeter Maydell     }
348175153179SPeter Maydell 
348275153179SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size);
348375153179SPeter Maydell 
348475153179SPeter Maydell     return true;
348575153179SPeter Maydell }
348675153179SPeter Maydell 
348775153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN)                                  \
348875153179SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
348975153179SPeter Maydell     {                                                           \
349075153179SPeter Maydell         return do_2misc_vec(s, a, FN);                          \
349175153179SPeter Maydell     }
349275153179SPeter Maydell 
349375153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg)
349475153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs)
349575153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0)
349675153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
349775153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
349875153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
349975153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
350075153179SPeter Maydell 
350175153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a)
350275153179SPeter Maydell {
350375153179SPeter Maydell     if (a->size != 0) {
350475153179SPeter Maydell         return false;
350575153179SPeter Maydell     }
350675153179SPeter Maydell     return do_2misc_vec(s, a, tcg_gen_gvec_not);
350775153179SPeter Maydell }
35080b30dd5bSPeter Maydell 
35090b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA)                          \
35100b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
35110b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
35120b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
35130b30dd5bSPeter Maydell     {                                                                   \
35140b30dd5bSPeter Maydell         tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz,        \
35150b30dd5bSPeter Maydell                            DATA, FUNC);                                 \
35160b30dd5bSPeter Maydell     }
35170b30dd5bSPeter Maydell 
35180b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA)                          \
35190b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
35200b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
35210b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
35220b30dd5bSPeter Maydell     {                                                                   \
35230b30dd5bSPeter Maydell         tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC);   \
35240b30dd5bSPeter Maydell     }
35250b30dd5bSPeter Maydell 
35260b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0)
35270b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1)
35280b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0)
35290b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1)
35300b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0)
35310b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0)
35320b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0)
35330b30dd5bSPeter Maydell 
35340b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE)                       \
35350b30dd5bSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
35360b30dd5bSPeter Maydell     {                                                           \
35370b30dd5bSPeter Maydell         if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) {  \
35380b30dd5bSPeter Maydell             return false;                                       \
35390b30dd5bSPeter Maydell         }                                                       \
35400b30dd5bSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                  \
35410b30dd5bSPeter Maydell     }
35420b30dd5bSPeter Maydell 
35430b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0)
35440b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0)
35450b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0)
35460b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
35470b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
35480b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
35490b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
3550