xref: /qemu/target/arm/tcg/translate-neon.c (revision e4a6d4a69e239becfd83bdcd996476e7b8e1138d)
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 */
53139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc"
54139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc"
55139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc"
56afff8de0SPeter Maydell 
576fb57878SPeter Maydell /* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
586fb57878SPeter Maydell  * where 0 is the least significant end of the register.
596fb57878SPeter Maydell  */
606fb57878SPeter Maydell static inline long
616fb57878SPeter Maydell neon_element_offset(int reg, int element, MemOp size)
626fb57878SPeter Maydell {
636fb57878SPeter Maydell     int element_size = 1 << size;
646fb57878SPeter Maydell     int ofs = element * element_size;
656fb57878SPeter Maydell #ifdef HOST_WORDS_BIGENDIAN
666fb57878SPeter Maydell     /* Calculate the offset assuming fully little-endian,
676fb57878SPeter Maydell      * then XOR to account for the order of the 8-byte units.
686fb57878SPeter Maydell      */
696fb57878SPeter Maydell     if (element_size < 8) {
706fb57878SPeter Maydell         ofs ^= 8 - element_size;
716fb57878SPeter Maydell     }
726fb57878SPeter Maydell #endif
736fb57878SPeter Maydell     return neon_reg_offset(reg, 0) + ofs;
746fb57878SPeter Maydell }
756fb57878SPeter Maydell 
766fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
776fb57878SPeter Maydell {
786fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
796fb57878SPeter Maydell 
806fb57878SPeter Maydell     switch (mop) {
816fb57878SPeter Maydell     case MO_UB:
826fb57878SPeter Maydell         tcg_gen_ld8u_i32(var, cpu_env, offset);
836fb57878SPeter Maydell         break;
846fb57878SPeter Maydell     case MO_UW:
856fb57878SPeter Maydell         tcg_gen_ld16u_i32(var, cpu_env, offset);
866fb57878SPeter Maydell         break;
876fb57878SPeter Maydell     case MO_UL:
886fb57878SPeter Maydell         tcg_gen_ld_i32(var, cpu_env, offset);
896fb57878SPeter Maydell         break;
906fb57878SPeter Maydell     default:
916fb57878SPeter Maydell         g_assert_not_reached();
926fb57878SPeter Maydell     }
936fb57878SPeter Maydell }
946fb57878SPeter Maydell 
956fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
966fb57878SPeter Maydell {
976fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
986fb57878SPeter Maydell 
996fb57878SPeter Maydell     switch (mop) {
1006fb57878SPeter Maydell     case MO_UB:
1016fb57878SPeter Maydell         tcg_gen_ld8u_i64(var, cpu_env, offset);
1026fb57878SPeter Maydell         break;
1036fb57878SPeter Maydell     case MO_UW:
1046fb57878SPeter Maydell         tcg_gen_ld16u_i64(var, cpu_env, offset);
1056fb57878SPeter Maydell         break;
1066fb57878SPeter Maydell     case MO_UL:
1076fb57878SPeter Maydell         tcg_gen_ld32u_i64(var, cpu_env, offset);
1086fb57878SPeter Maydell         break;
1096fb57878SPeter Maydell     case MO_Q:
1106fb57878SPeter Maydell         tcg_gen_ld_i64(var, cpu_env, offset);
1116fb57878SPeter Maydell         break;
1126fb57878SPeter Maydell     default:
1136fb57878SPeter Maydell         g_assert_not_reached();
1146fb57878SPeter Maydell     }
1156fb57878SPeter Maydell }
1166fb57878SPeter Maydell 
1176fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
1186fb57878SPeter Maydell {
1196fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
1206fb57878SPeter Maydell 
1216fb57878SPeter Maydell     switch (size) {
1226fb57878SPeter Maydell     case MO_8:
1236fb57878SPeter Maydell         tcg_gen_st8_i32(var, cpu_env, offset);
1246fb57878SPeter Maydell         break;
1256fb57878SPeter Maydell     case MO_16:
1266fb57878SPeter Maydell         tcg_gen_st16_i32(var, cpu_env, offset);
1276fb57878SPeter Maydell         break;
1286fb57878SPeter Maydell     case MO_32:
1296fb57878SPeter Maydell         tcg_gen_st_i32(var, cpu_env, offset);
1306fb57878SPeter Maydell         break;
1316fb57878SPeter Maydell     default:
1326fb57878SPeter Maydell         g_assert_not_reached();
1336fb57878SPeter Maydell     }
1346fb57878SPeter Maydell }
1356fb57878SPeter Maydell 
1366fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
1376fb57878SPeter Maydell {
1386fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
1396fb57878SPeter Maydell 
1406fb57878SPeter Maydell     switch (size) {
1416fb57878SPeter Maydell     case MO_8:
1426fb57878SPeter Maydell         tcg_gen_st8_i64(var, cpu_env, offset);
1436fb57878SPeter Maydell         break;
1446fb57878SPeter Maydell     case MO_16:
1456fb57878SPeter Maydell         tcg_gen_st16_i64(var, cpu_env, offset);
1466fb57878SPeter Maydell         break;
1476fb57878SPeter Maydell     case MO_32:
1486fb57878SPeter Maydell         tcg_gen_st32_i64(var, cpu_env, offset);
1496fb57878SPeter Maydell         break;
1506fb57878SPeter Maydell     case MO_64:
1516fb57878SPeter Maydell         tcg_gen_st_i64(var, cpu_env, offset);
1526fb57878SPeter Maydell         break;
1536fb57878SPeter Maydell     default:
1546fb57878SPeter Maydell         g_assert_not_reached();
1556fb57878SPeter Maydell     }
1566fb57878SPeter Maydell }
1576fb57878SPeter Maydell 
158afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
159afff8de0SPeter Maydell {
160afff8de0SPeter Maydell     int opr_sz;
161afff8de0SPeter Maydell     TCGv_ptr fpst;
162afff8de0SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
163afff8de0SPeter Maydell 
164afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
165afff8de0SPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
166afff8de0SPeter Maydell         return false;
167afff8de0SPeter Maydell     }
168afff8de0SPeter Maydell 
169afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
170afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
171afff8de0SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
172afff8de0SPeter Maydell         return false;
173afff8de0SPeter Maydell     }
174afff8de0SPeter Maydell 
175afff8de0SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
176afff8de0SPeter Maydell         return false;
177afff8de0SPeter Maydell     }
178afff8de0SPeter Maydell 
179afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
180afff8de0SPeter Maydell         return true;
181afff8de0SPeter Maydell     }
182afff8de0SPeter Maydell 
183afff8de0SPeter Maydell     opr_sz = (1 + a->q) * 8;
184b34aa512SPeter Maydell     fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD);
185afff8de0SPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
186afff8de0SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
187afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vn),
188afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vm),
189afff8de0SPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
190afff8de0SPeter Maydell                        fn_gvec_ptr);
191afff8de0SPeter Maydell     tcg_temp_free_ptr(fpst);
192afff8de0SPeter Maydell     return true;
193afff8de0SPeter Maydell }
19494d5eb7bSPeter Maydell 
19594d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
19694d5eb7bSPeter Maydell {
19794d5eb7bSPeter Maydell     int opr_sz;
19894d5eb7bSPeter Maydell     TCGv_ptr fpst;
19994d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
20094d5eb7bSPeter Maydell 
20194d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
20294d5eb7bSPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
20394d5eb7bSPeter Maydell         return false;
20494d5eb7bSPeter Maydell     }
20594d5eb7bSPeter Maydell 
20694d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
20794d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
20894d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
20994d5eb7bSPeter Maydell         return false;
21094d5eb7bSPeter Maydell     }
21194d5eb7bSPeter Maydell 
21294d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
21394d5eb7bSPeter Maydell         return false;
21494d5eb7bSPeter Maydell     }
21594d5eb7bSPeter Maydell 
21694d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
21794d5eb7bSPeter Maydell         return true;
21894d5eb7bSPeter Maydell     }
21994d5eb7bSPeter Maydell 
22094d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
221b34aa512SPeter Maydell     fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD);
22294d5eb7bSPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
22394d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
22494d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
22594d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
22694d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
22794d5eb7bSPeter Maydell                        fn_gvec_ptr);
22894d5eb7bSPeter Maydell     tcg_temp_free_ptr(fpst);
22994d5eb7bSPeter Maydell     return true;
23094d5eb7bSPeter Maydell }
23132da0e33SPeter Maydell 
23232da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
23332da0e33SPeter Maydell {
23432da0e33SPeter Maydell     int opr_sz;
23532da0e33SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
23632da0e33SPeter Maydell 
23732da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
23832da0e33SPeter Maydell         return false;
23932da0e33SPeter Maydell     }
24032da0e33SPeter Maydell 
24132da0e33SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
24232da0e33SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
24332da0e33SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
24432da0e33SPeter Maydell         return false;
24532da0e33SPeter Maydell     }
24632da0e33SPeter Maydell 
24732da0e33SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
24832da0e33SPeter Maydell         return false;
24932da0e33SPeter Maydell     }
25032da0e33SPeter Maydell 
25132da0e33SPeter Maydell     if (!vfp_access_check(s)) {
25232da0e33SPeter Maydell         return true;
25332da0e33SPeter Maydell     }
25432da0e33SPeter Maydell 
25532da0e33SPeter Maydell     opr_sz = (1 + a->q) * 8;
25632da0e33SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
25732da0e33SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
25832da0e33SPeter Maydell                        vfp_reg_offset(1, a->vn),
25932da0e33SPeter Maydell                        vfp_reg_offset(1, a->vm),
26032da0e33SPeter Maydell                        opr_sz, opr_sz, 0, fn_gvec);
26132da0e33SPeter Maydell     return true;
26232da0e33SPeter Maydell }
2639a107e7bSPeter Maydell 
2649a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
2659a107e7bSPeter Maydell {
2669a107e7bSPeter Maydell     int opr_sz;
2679a107e7bSPeter Maydell 
2689a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
2699a107e7bSPeter Maydell         return false;
2709a107e7bSPeter Maydell     }
2719a107e7bSPeter Maydell 
2729a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2739a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2749a107e7bSPeter Maydell         (a->vd & 0x10)) {
2759a107e7bSPeter Maydell         return false;
2769a107e7bSPeter Maydell     }
2779a107e7bSPeter Maydell 
2789a107e7bSPeter Maydell     if (a->vd & a->q) {
2799a107e7bSPeter Maydell         return false;
2809a107e7bSPeter Maydell     }
2819a107e7bSPeter Maydell 
2829a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
2839a107e7bSPeter Maydell         return true;
2849a107e7bSPeter Maydell     }
2859a107e7bSPeter Maydell 
2869a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
2879a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
2889a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
2899a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
2909a107e7bSPeter Maydell                        cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
2919a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
2929a107e7bSPeter Maydell     return true;
2939a107e7bSPeter Maydell }
2947e1b5d61SPeter Maydell 
2957e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
2967e1b5d61SPeter Maydell {
2977e1b5d61SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
2987e1b5d61SPeter Maydell     int opr_sz;
2997e1b5d61SPeter Maydell     TCGv_ptr fpst;
3007e1b5d61SPeter Maydell 
3017e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
3027e1b5d61SPeter Maydell         return false;
3037e1b5d61SPeter Maydell     }
3047e1b5d61SPeter Maydell     if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) {
3057e1b5d61SPeter Maydell         return false;
3067e1b5d61SPeter Maydell     }
3077e1b5d61SPeter Maydell 
3087e1b5d61SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3097e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3107e1b5d61SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
3117e1b5d61SPeter Maydell         return false;
3127e1b5d61SPeter Maydell     }
3137e1b5d61SPeter Maydell 
3147e1b5d61SPeter Maydell     if ((a->vd | a->vn) & a->q) {
3157e1b5d61SPeter Maydell         return false;
3167e1b5d61SPeter Maydell     }
3177e1b5d61SPeter Maydell 
3187e1b5d61SPeter Maydell     if (!vfp_access_check(s)) {
3197e1b5d61SPeter Maydell         return true;
3207e1b5d61SPeter Maydell     }
3217e1b5d61SPeter Maydell 
3227e1b5d61SPeter Maydell     fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx
3237e1b5d61SPeter Maydell                    : gen_helper_gvec_fcmlah_idx);
3247e1b5d61SPeter Maydell     opr_sz = (1 + a->q) * 8;
325b34aa512SPeter Maydell     fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD);
3267e1b5d61SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
3277e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vn),
3287e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vm),
3297e1b5d61SPeter Maydell                        fpst, opr_sz, opr_sz,
3307e1b5d61SPeter Maydell                        (a->index << 2) | a->rot, fn_gvec_ptr);
3317e1b5d61SPeter Maydell     tcg_temp_free_ptr(fpst);
3327e1b5d61SPeter Maydell     return true;
3337e1b5d61SPeter Maydell }
33435f5d4d1SPeter Maydell 
33535f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
33635f5d4d1SPeter Maydell {
33735f5d4d1SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
33835f5d4d1SPeter Maydell     int opr_sz;
33935f5d4d1SPeter Maydell     TCGv_ptr fpst;
34035f5d4d1SPeter Maydell 
34135f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
34235f5d4d1SPeter Maydell         return false;
34335f5d4d1SPeter Maydell     }
34435f5d4d1SPeter Maydell 
34535f5d4d1SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
34635f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
34735f5d4d1SPeter Maydell         ((a->vd | a->vn) & 0x10)) {
34835f5d4d1SPeter Maydell         return false;
34935f5d4d1SPeter Maydell     }
35035f5d4d1SPeter Maydell 
35135f5d4d1SPeter Maydell     if ((a->vd | a->vn) & a->q) {
35235f5d4d1SPeter Maydell         return false;
35335f5d4d1SPeter Maydell     }
35435f5d4d1SPeter Maydell 
35535f5d4d1SPeter Maydell     if (!vfp_access_check(s)) {
35635f5d4d1SPeter Maydell         return true;
35735f5d4d1SPeter Maydell     }
35835f5d4d1SPeter Maydell 
35935f5d4d1SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
36035f5d4d1SPeter Maydell     opr_sz = (1 + a->q) * 8;
361a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
36235f5d4d1SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
36335f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->vn),
36435f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->rm),
36535f5d4d1SPeter Maydell                        opr_sz, opr_sz, a->index, fn_gvec);
36635f5d4d1SPeter Maydell     tcg_temp_free_ptr(fpst);
36735f5d4d1SPeter Maydell     return true;
36835f5d4d1SPeter Maydell }
369d27e82f7SPeter Maydell 
370d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
371d27e82f7SPeter Maydell {
372d27e82f7SPeter Maydell     int opr_sz;
373d27e82f7SPeter Maydell 
374d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
375d27e82f7SPeter Maydell         return false;
376d27e82f7SPeter Maydell     }
377d27e82f7SPeter Maydell 
378d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
379d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
380d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
381d27e82f7SPeter Maydell         return false;
382d27e82f7SPeter Maydell     }
383d27e82f7SPeter Maydell 
384d27e82f7SPeter Maydell     if (a->vd & a->q) {
385d27e82f7SPeter Maydell         return false;
386d27e82f7SPeter Maydell     }
387d27e82f7SPeter Maydell 
388d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
389d27e82f7SPeter Maydell         return true;
390d27e82f7SPeter Maydell     }
391d27e82f7SPeter Maydell 
392d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
393d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
394d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
395d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
396d27e82f7SPeter Maydell                        cpu_env, opr_sz, opr_sz,
397d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
398d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
399d27e82f7SPeter Maydell     return true;
400d27e82f7SPeter Maydell }
401a27b4630SPeter Maydell 
402a27b4630SPeter Maydell static struct {
403a27b4630SPeter Maydell     int nregs;
404a27b4630SPeter Maydell     int interleave;
405a27b4630SPeter Maydell     int spacing;
406a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
407a27b4630SPeter Maydell     {1, 4, 1},
408a27b4630SPeter Maydell     {1, 4, 2},
409a27b4630SPeter Maydell     {4, 1, 1},
410a27b4630SPeter Maydell     {2, 2, 2},
411a27b4630SPeter Maydell     {1, 3, 1},
412a27b4630SPeter Maydell     {1, 3, 2},
413a27b4630SPeter Maydell     {3, 1, 1},
414a27b4630SPeter Maydell     {1, 1, 1},
415a27b4630SPeter Maydell     {1, 2, 1},
416a27b4630SPeter Maydell     {1, 2, 2},
417a27b4630SPeter Maydell     {2, 1, 1}
418a27b4630SPeter Maydell };
419a27b4630SPeter Maydell 
420a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
421a27b4630SPeter Maydell                                       int stride)
422a27b4630SPeter Maydell {
423a27b4630SPeter Maydell     if (rm != 15) {
424a27b4630SPeter Maydell         TCGv_i32 base;
425a27b4630SPeter Maydell 
426a27b4630SPeter Maydell         base = load_reg(s, rn);
427a27b4630SPeter Maydell         if (rm == 13) {
428a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
429a27b4630SPeter Maydell         } else {
430a27b4630SPeter Maydell             TCGv_i32 index;
431a27b4630SPeter Maydell             index = load_reg(s, rm);
432a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
433a27b4630SPeter Maydell             tcg_temp_free_i32(index);
434a27b4630SPeter Maydell         }
435a27b4630SPeter Maydell         store_reg(s, rn, base);
436a27b4630SPeter Maydell     }
437a27b4630SPeter Maydell }
438a27b4630SPeter Maydell 
439a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
440a27b4630SPeter Maydell {
441a27b4630SPeter Maydell     /* Neon load/store multiple structures */
442a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
443a27b4630SPeter Maydell     MemOp endian = s->be_data;
444a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
445a27b4630SPeter Maydell     int size = a->size;
446a27b4630SPeter Maydell     TCGv_i64 tmp64;
447a27b4630SPeter Maydell     TCGv_i32 addr, tmp;
448a27b4630SPeter Maydell 
449a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
450a27b4630SPeter Maydell         return false;
451a27b4630SPeter Maydell     }
452a27b4630SPeter Maydell 
453a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
454a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
455a27b4630SPeter Maydell         return false;
456a27b4630SPeter Maydell     }
457a27b4630SPeter Maydell     if (a->itype > 10) {
458a27b4630SPeter Maydell         return false;
459a27b4630SPeter Maydell     }
460a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
461a27b4630SPeter Maydell     switch (a->itype & 0xc) {
462a27b4630SPeter Maydell     case 4:
463a27b4630SPeter Maydell         if (a->align >= 2) {
464a27b4630SPeter Maydell             return false;
465a27b4630SPeter Maydell         }
466a27b4630SPeter Maydell         break;
467a27b4630SPeter Maydell     case 8:
468a27b4630SPeter Maydell         if (a->align == 3) {
469a27b4630SPeter Maydell             return false;
470a27b4630SPeter Maydell         }
471a27b4630SPeter Maydell         break;
472a27b4630SPeter Maydell     default:
473a27b4630SPeter Maydell         break;
474a27b4630SPeter Maydell     }
475a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
476a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
477a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
478a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
479a27b4630SPeter Maydell         return false;
480a27b4630SPeter Maydell     }
481a27b4630SPeter Maydell 
482a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
483a27b4630SPeter Maydell         return true;
484a27b4630SPeter Maydell     }
485a27b4630SPeter Maydell 
486a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
487a27b4630SPeter Maydell     if (size == 0) {
488a27b4630SPeter Maydell         endian = MO_LE;
489a27b4630SPeter Maydell     }
490a27b4630SPeter Maydell     /*
491a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
492a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
493a27b4630SPeter Maydell      */
494a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
495a27b4630SPeter Maydell         size = 3;
496a27b4630SPeter Maydell     }
497a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
498a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
499a27b4630SPeter Maydell     tmp = tcg_const_i32(1 << size);
500a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
501a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
502a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
503a27b4630SPeter Maydell             int xs;
504a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
505a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
506a27b4630SPeter Maydell 
507a27b4630SPeter Maydell                 if (a->l) {
508a27b4630SPeter Maydell                     gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
509a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
510a27b4630SPeter Maydell                 } else {
511a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
512a27b4630SPeter Maydell                     gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
513a27b4630SPeter Maydell                 }
514a27b4630SPeter Maydell                 tcg_gen_add_i32(addr, addr, tmp);
515a27b4630SPeter Maydell             }
516a27b4630SPeter Maydell         }
517a27b4630SPeter Maydell     }
518a27b4630SPeter Maydell     tcg_temp_free_i32(addr);
519a27b4630SPeter Maydell     tcg_temp_free_i32(tmp);
520a27b4630SPeter Maydell     tcg_temp_free_i64(tmp64);
521a27b4630SPeter Maydell 
522a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
523a27b4630SPeter Maydell     return true;
524a27b4630SPeter Maydell }
5253698747cSPeter Maydell 
5263698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
5273698747cSPeter Maydell {
5283698747cSPeter Maydell     /* Neon load single structure to all lanes */
5293698747cSPeter Maydell     int reg, stride, vec_size;
5303698747cSPeter Maydell     int vd = a->vd;
5313698747cSPeter Maydell     int size = a->size;
5323698747cSPeter Maydell     int nregs = a->n + 1;
5333698747cSPeter Maydell     TCGv_i32 addr, tmp;
5343698747cSPeter Maydell 
5353698747cSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
5363698747cSPeter Maydell         return false;
5373698747cSPeter Maydell     }
5383698747cSPeter Maydell 
5393698747cSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
5403698747cSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
5413698747cSPeter Maydell         return false;
5423698747cSPeter Maydell     }
5433698747cSPeter Maydell 
5443698747cSPeter Maydell     if (size == 3) {
5453698747cSPeter Maydell         if (nregs != 4 || a->a == 0) {
5463698747cSPeter Maydell             return false;
5473698747cSPeter Maydell         }
5483698747cSPeter Maydell         /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
5493698747cSPeter Maydell         size = 2;
5503698747cSPeter Maydell     }
5513698747cSPeter Maydell     if (nregs == 1 && a->a == 1 && size == 0) {
5523698747cSPeter Maydell         return false;
5533698747cSPeter Maydell     }
5543698747cSPeter Maydell     if (nregs == 3 && a->a == 1) {
5553698747cSPeter Maydell         return false;
5563698747cSPeter Maydell     }
5573698747cSPeter Maydell 
5583698747cSPeter Maydell     if (!vfp_access_check(s)) {
5593698747cSPeter Maydell         return true;
5603698747cSPeter Maydell     }
5613698747cSPeter Maydell 
5623698747cSPeter Maydell     /*
5633698747cSPeter Maydell      * VLD1 to all lanes: T bit indicates how many Dregs to write.
5643698747cSPeter Maydell      * VLD2/3/4 to all lanes: T bit indicates register stride.
5653698747cSPeter Maydell      */
5663698747cSPeter Maydell     stride = a->t ? 2 : 1;
5673698747cSPeter Maydell     vec_size = nregs == 1 ? stride * 8 : 8;
5683698747cSPeter Maydell 
5693698747cSPeter Maydell     tmp = tcg_temp_new_i32();
5703698747cSPeter Maydell     addr = tcg_temp_new_i32();
5713698747cSPeter Maydell     load_reg_var(s, addr, a->rn);
5723698747cSPeter Maydell     for (reg = 0; reg < nregs; reg++) {
5733698747cSPeter Maydell         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
5743698747cSPeter Maydell                         s->be_data | size);
5753698747cSPeter Maydell         if ((vd & 1) && vec_size == 16) {
5763698747cSPeter Maydell             /*
5773698747cSPeter Maydell              * We cannot write 16 bytes at once because the
5783698747cSPeter Maydell              * destination is unaligned.
5793698747cSPeter Maydell              */
5803698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
5813698747cSPeter Maydell                                  8, 8, tmp);
5823698747cSPeter Maydell             tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0),
5833698747cSPeter Maydell                              neon_reg_offset(vd, 0), 8, 8);
5843698747cSPeter Maydell         } else {
5853698747cSPeter Maydell             tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0),
5863698747cSPeter Maydell                                  vec_size, vec_size, tmp);
5873698747cSPeter Maydell         }
5883698747cSPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << size);
5893698747cSPeter Maydell         vd += stride;
5903698747cSPeter Maydell     }
5913698747cSPeter Maydell     tcg_temp_free_i32(tmp);
5923698747cSPeter Maydell     tcg_temp_free_i32(addr);
5933698747cSPeter Maydell 
5943698747cSPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
5953698747cSPeter Maydell 
5963698747cSPeter Maydell     return true;
5973698747cSPeter Maydell }
598123ce4e3SPeter Maydell 
599123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
600123ce4e3SPeter Maydell {
601123ce4e3SPeter Maydell     /* Neon load/store single structure to one lane */
602123ce4e3SPeter Maydell     int reg;
603123ce4e3SPeter Maydell     int nregs = a->n + 1;
604123ce4e3SPeter Maydell     int vd = a->vd;
605123ce4e3SPeter Maydell     TCGv_i32 addr, tmp;
606123ce4e3SPeter Maydell 
607123ce4e3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
608123ce4e3SPeter Maydell         return false;
609123ce4e3SPeter Maydell     }
610123ce4e3SPeter Maydell 
611123ce4e3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
612123ce4e3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
613123ce4e3SPeter Maydell         return false;
614123ce4e3SPeter Maydell     }
615123ce4e3SPeter Maydell 
616123ce4e3SPeter Maydell     /* Catch the UNDEF cases. This is unavoidably a bit messy. */
617123ce4e3SPeter Maydell     switch (nregs) {
618123ce4e3SPeter Maydell     case 1:
619123ce4e3SPeter Maydell         if (((a->align & (1 << a->size)) != 0) ||
620123ce4e3SPeter Maydell             (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) {
621123ce4e3SPeter Maydell             return false;
622123ce4e3SPeter Maydell         }
623123ce4e3SPeter Maydell         break;
624123ce4e3SPeter Maydell     case 3:
625123ce4e3SPeter Maydell         if ((a->align & 1) != 0) {
626123ce4e3SPeter Maydell             return false;
627123ce4e3SPeter Maydell         }
628123ce4e3SPeter Maydell         /* fall through */
629123ce4e3SPeter Maydell     case 2:
630123ce4e3SPeter Maydell         if (a->size == 2 && (a->align & 2) != 0) {
631123ce4e3SPeter Maydell             return false;
632123ce4e3SPeter Maydell         }
633123ce4e3SPeter Maydell         break;
634123ce4e3SPeter Maydell     case 4:
635123ce4e3SPeter Maydell         if ((a->size == 2) && ((a->align & 3) == 3)) {
636123ce4e3SPeter Maydell             return false;
637123ce4e3SPeter Maydell         }
638123ce4e3SPeter Maydell         break;
639123ce4e3SPeter Maydell     default:
640123ce4e3SPeter Maydell         abort();
641123ce4e3SPeter Maydell     }
642123ce4e3SPeter Maydell     if ((vd + a->stride * (nregs - 1)) > 31) {
643123ce4e3SPeter Maydell         /*
644123ce4e3SPeter Maydell          * Attempts to write off the end of the register file are
645123ce4e3SPeter Maydell          * UNPREDICTABLE; we choose to UNDEF because otherwise we would
646123ce4e3SPeter Maydell          * access off the end of the array that holds the register data.
647123ce4e3SPeter Maydell          */
648123ce4e3SPeter Maydell         return false;
649123ce4e3SPeter Maydell     }
650123ce4e3SPeter Maydell 
651123ce4e3SPeter Maydell     if (!vfp_access_check(s)) {
652123ce4e3SPeter Maydell         return true;
653123ce4e3SPeter Maydell     }
654123ce4e3SPeter Maydell 
655123ce4e3SPeter Maydell     tmp = tcg_temp_new_i32();
656123ce4e3SPeter Maydell     addr = tcg_temp_new_i32();
657123ce4e3SPeter Maydell     load_reg_var(s, addr, a->rn);
658123ce4e3SPeter Maydell     /*
659123ce4e3SPeter Maydell      * TODO: if we implemented alignment exceptions, we should check
660123ce4e3SPeter Maydell      * addr against the alignment encoded in a->align here.
661123ce4e3SPeter Maydell      */
662123ce4e3SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
663123ce4e3SPeter Maydell         if (a->l) {
664123ce4e3SPeter Maydell             gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
665123ce4e3SPeter Maydell                             s->be_data | a->size);
666123ce4e3SPeter Maydell             neon_store_element(vd, a->reg_idx, a->size, tmp);
667123ce4e3SPeter Maydell         } else { /* Store */
668123ce4e3SPeter Maydell             neon_load_element(tmp, vd, a->reg_idx, a->size);
669123ce4e3SPeter Maydell             gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
670123ce4e3SPeter Maydell                             s->be_data | a->size);
671123ce4e3SPeter Maydell         }
672123ce4e3SPeter Maydell         vd += a->stride;
673123ce4e3SPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << a->size);
674123ce4e3SPeter Maydell     }
675123ce4e3SPeter Maydell     tcg_temp_free_i32(addr);
676123ce4e3SPeter Maydell     tcg_temp_free_i32(tmp);
677123ce4e3SPeter Maydell 
678123ce4e3SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
679123ce4e3SPeter Maydell 
680123ce4e3SPeter Maydell     return true;
681123ce4e3SPeter Maydell }
682a4e143acSPeter Maydell 
683a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
684a4e143acSPeter Maydell {
685a4e143acSPeter Maydell     int vec_size = a->q ? 16 : 8;
686a4e143acSPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
687a4e143acSPeter Maydell     int rn_ofs = neon_reg_offset(a->vn, 0);
688a4e143acSPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
689a4e143acSPeter Maydell 
690a4e143acSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
691a4e143acSPeter Maydell         return false;
692a4e143acSPeter Maydell     }
693a4e143acSPeter Maydell 
694a4e143acSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
695a4e143acSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
696a4e143acSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
697a4e143acSPeter Maydell         return false;
698a4e143acSPeter Maydell     }
699a4e143acSPeter Maydell 
700a4e143acSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
701a4e143acSPeter Maydell         return false;
702a4e143acSPeter Maydell     }
703a4e143acSPeter Maydell 
704a4e143acSPeter Maydell     if (!vfp_access_check(s)) {
705a4e143acSPeter Maydell         return true;
706a4e143acSPeter Maydell     }
707a4e143acSPeter Maydell 
708a4e143acSPeter Maydell     fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
709a4e143acSPeter Maydell     return true;
710a4e143acSPeter Maydell }
711a4e143acSPeter Maydell 
712a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC)                                            \
713a4e143acSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
714a4e143acSPeter Maydell     {                                                                   \
715a4e143acSPeter Maydell         return do_3same(s, a, FUNC);                                    \
716a4e143acSPeter Maydell     }
717a4e143acSPeter Maydell 
718a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add)
719a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub)
72035a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and)
72135a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc)
72235a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or)
72335a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc)
72435a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor)
7258161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl)
7268161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl)
727c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc)
728c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc)
729c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc)
730c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc)
73135a548edSPeter Maydell 
73235a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */
73335a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3)                               \
73435a548edSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
73535a548edSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
73635a548edSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
73735a548edSPeter Maydell     {                                                                   \
73835a548edSPeter Maydell         tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz);    \
73935a548edSPeter Maydell     }                                                                   \
74035a548edSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
74135a548edSPeter Maydell 
74235a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
74335a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
74435a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
74536b59310SPeter Maydell 
74636b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC)                                    \
74736b59310SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
74836b59310SPeter Maydell     {                                                                   \
74936b59310SPeter Maydell         if (a->size == 3) {                                             \
75036b59310SPeter Maydell             return false;                                               \
75136b59310SPeter Maydell         }                                                               \
75236b59310SPeter Maydell         return do_3same(s, a, FUNC);                                    \
75336b59310SPeter Maydell     }
75436b59310SPeter Maydell 
75536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
75636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
75736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
75836b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
7590de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
76027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla)
76127106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls)
7628161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst)
7637715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd)
7647715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba)
7657715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd)
7667715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba)
76702bd0cdbSPeter Maydell 
76802bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND)                                        \
76902bd0cdbSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
77002bd0cdbSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
77102bd0cdbSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
77202bd0cdbSPeter Maydell     {                                                                   \
77302bd0cdbSPeter Maydell         tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
77402bd0cdbSPeter Maydell     }                                                                   \
77502bd0cdbSPeter Maydell     DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
77602bd0cdbSPeter Maydell 
77702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
77802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
77902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
78002bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
78102bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
78202bd0cdbSPeter Maydell 
783effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC)                                        \
784effa992fSRichard Henderson     static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,  \
785effa992fSRichard Henderson                          uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)  \
786effa992fSRichard Henderson     {                                                                      \
787effa992fSRichard Henderson         tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \
7880de34fd4SPeter Maydell     }
7890de34fd4SPeter Maydell 
790effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b)
791effa992fSRichard Henderson 
7920de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
7930de34fd4SPeter Maydell {
7940de34fd4SPeter Maydell     if (a->size != 0) {
7950de34fd4SPeter Maydell         return false;
7960de34fd4SPeter Maydell     }
7970de34fd4SPeter Maydell     return do_3same(s, a, gen_VMUL_p_3s);
7980de34fd4SPeter Maydell }
799a0635695SPeter Maydell 
800a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC)                                         \
801a0635695SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
802a0635695SPeter Maydell     {                                                                   \
803a0635695SPeter Maydell         if (!dc_isar_feature(aa32_rdm, s)) {                            \
804a0635695SPeter Maydell             return false;                                               \
805a0635695SPeter Maydell         }                                                               \
806a0635695SPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
807a0635695SPeter Maydell             return false;                                               \
808a0635695SPeter Maydell         }                                                               \
809a0635695SPeter Maydell         return do_3same(s, a, FUNC);                                    \
810a0635695SPeter Maydell     }
811a0635695SPeter Maydell 
812a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc)
813a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc)
81421290edfSPeter Maydell 
815afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC)                                             \
816afc8b7d3SRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
817afc8b7d3SRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
818afc8b7d3SRichard Henderson     {                                                                   \
819afc8b7d3SRichard Henderson         if (!dc_isar_feature(aa32_sha1, s)) {                           \
820afc8b7d3SRichard Henderson             return false;                                               \
821afc8b7d3SRichard Henderson         }                                                               \
822afc8b7d3SRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
82321290edfSPeter Maydell     }
82421290edfSPeter Maydell 
825afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c)
826afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p)
827afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m)
828afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0)
82921290edfSPeter Maydell 
830effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC)                                             \
831effa992fSRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
832effa992fSRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
833effa992fSRichard Henderson     {                                                                   \
834effa992fSRichard Henderson         if (!dc_isar_feature(aa32_sha2, s)) {                           \
835effa992fSRichard Henderson             return false;                                               \
836effa992fSRichard Henderson         }                                                               \
837effa992fSRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
83821290edfSPeter Maydell     }
83921290edfSPeter Maydell 
840effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h)
841effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2)
842effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1)
84335d4352fSPeter Maydell 
84435d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC)                                         \
84535d4352fSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
84635d4352fSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
84735d4352fSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
84835d4352fSPeter Maydell     {                                                                   \
84935d4352fSPeter Maydell         static const GVecGen3 op = { .fni8 = FUNC };                    \
85035d4352fSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op);      \
85135d4352fSPeter Maydell     }                                                                   \
85235d4352fSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
85335d4352fSPeter Maydell 
85435d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC)                                     \
85535d4352fSPeter Maydell     static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)    \
85635d4352fSPeter Maydell     {                                                                   \
85735d4352fSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
85835d4352fSPeter Maydell     }                                                                   \
85935d4352fSPeter Maydell     DO_3SAME_64(INSN, gen_##INSN##_elt)
86035d4352fSPeter Maydell 
86135d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64)
86235d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64)
86335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64)
86435d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64)
86535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64)
86635d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64)
867cb294bcaSPeter Maydell 
868cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC)                                         \
869cb294bcaSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
870cb294bcaSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
871cb294bcaSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
872cb294bcaSPeter Maydell     {                                                                   \
873cb294bcaSPeter Maydell         static const GVecGen3 ops[4] = {                                \
874cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##8 },                      \
875cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##16 },                     \
876cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##32 },                     \
877cb294bcaSPeter Maydell             { 0 },                                                      \
878cb294bcaSPeter Maydell         };                                                              \
879cb294bcaSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
880cb294bcaSPeter Maydell     }                                                                   \
881cb294bcaSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
882cb294bcaSPeter Maydell     {                                                                   \
883cb294bcaSPeter Maydell         if (a->size > 2) {                                              \
884cb294bcaSPeter Maydell             return false;                                               \
885cb294bcaSPeter Maydell         }                                                               \
886cb294bcaSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
887cb294bcaSPeter Maydell     }
888cb294bcaSPeter Maydell 
8896812dfdcSPeter Maydell /*
8906812dfdcSPeter Maydell  * Some helper functions need to be passed the cpu_env. In order
8916812dfdcSPeter Maydell  * to use those with the gvec APIs like tcg_gen_gvec_3() we need
8926812dfdcSPeter Maydell  * to create wrapper functions whose prototype is a NeonGenTwoOpFn()
8936812dfdcSPeter Maydell  * and which call a NeonGenTwoOpEnvFn().
8946812dfdcSPeter Maydell  */
8956812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC)                                     \
8966812dfdcSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m)            \
8976812dfdcSPeter Maydell     {                                                                   \
8986812dfdcSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
8996812dfdcSPeter Maydell     }
9006812dfdcSPeter Maydell 
9016812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC)                                     \
9026812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8);        \
9036812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16);      \
9046812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32);      \
9056812dfdcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
9066812dfdcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
9076812dfdcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
9086812dfdcSPeter Maydell     {                                                                   \
9096812dfdcSPeter Maydell         static const GVecGen3 ops[4] = {                                \
9106812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp8 },                            \
9116812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
9126812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
9136812dfdcSPeter Maydell             { 0 },                                                      \
9146812dfdcSPeter Maydell         };                                                              \
9156812dfdcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
9166812dfdcSPeter Maydell     }                                                                   \
9176812dfdcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
9186812dfdcSPeter Maydell     {                                                                   \
9196812dfdcSPeter Maydell         if (a->size > 2) {                                              \
9206812dfdcSPeter Maydell             return false;                                               \
9216812dfdcSPeter Maydell         }                                                               \
9226812dfdcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
9236812dfdcSPeter Maydell     }
9246812dfdcSPeter Maydell 
925cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s)
926cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u)
9278e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s)
9288e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u)
9298e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s)
9308e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u)
9316812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s)
9326812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u)
9336812dfdcSPeter Maydell 
9346812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s)
9356812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u)
9366812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s)
9376812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u)
938059c2398SPeter Maydell 
939059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn)
940059c2398SPeter Maydell {
941059c2398SPeter Maydell     /* Operations handled pairwise 32 bits at a time */
942059c2398SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3;
943059c2398SPeter Maydell 
944059c2398SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
945059c2398SPeter Maydell         return false;
946059c2398SPeter Maydell     }
947059c2398SPeter Maydell 
948059c2398SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
949059c2398SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
950059c2398SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
951059c2398SPeter Maydell         return false;
952059c2398SPeter Maydell     }
953059c2398SPeter Maydell 
954059c2398SPeter Maydell     if (a->size == 3) {
955059c2398SPeter Maydell         return false;
956059c2398SPeter Maydell     }
957059c2398SPeter Maydell 
958059c2398SPeter Maydell     if (!vfp_access_check(s)) {
959059c2398SPeter Maydell         return true;
960059c2398SPeter Maydell     }
961059c2398SPeter Maydell 
962059c2398SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
963059c2398SPeter Maydell 
964059c2398SPeter Maydell     /*
965059c2398SPeter Maydell      * Note that we have to be careful not to clobber the source operands
966059c2398SPeter Maydell      * in the "vm == vd" case by storing the result of the first pass too
967059c2398SPeter Maydell      * early. Since Q is 0 there are always just two passes, so instead
968059c2398SPeter Maydell      * of a complicated loop over each pass we just unroll.
969059c2398SPeter Maydell      */
970059c2398SPeter Maydell     tmp = neon_load_reg(a->vn, 0);
971059c2398SPeter Maydell     tmp2 = neon_load_reg(a->vn, 1);
972059c2398SPeter Maydell     fn(tmp, tmp, tmp2);
973059c2398SPeter Maydell     tcg_temp_free_i32(tmp2);
974059c2398SPeter Maydell 
975059c2398SPeter Maydell     tmp3 = neon_load_reg(a->vm, 0);
976059c2398SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
977059c2398SPeter Maydell     fn(tmp3, tmp3, tmp2);
978059c2398SPeter Maydell     tcg_temp_free_i32(tmp2);
979059c2398SPeter Maydell 
980059c2398SPeter Maydell     neon_store_reg(a->vd, 0, tmp);
981059c2398SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
982059c2398SPeter Maydell     return true;
983059c2398SPeter Maydell }
984059c2398SPeter Maydell 
985059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func)                                       \
986059c2398SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
987059c2398SPeter Maydell     {                                                                   \
988059c2398SPeter Maydell         static NeonGenTwoOpFn * const fns[] = {                         \
989059c2398SPeter Maydell             gen_helper_neon_##func##8,                                  \
990059c2398SPeter Maydell             gen_helper_neon_##func##16,                                 \
991059c2398SPeter Maydell             gen_helper_neon_##func##32,                                 \
992059c2398SPeter Maydell         };                                                              \
993059c2398SPeter Maydell         if (a->size > 2) {                                              \
994059c2398SPeter Maydell             return false;                                               \
995059c2398SPeter Maydell         }                                                               \
996059c2398SPeter Maydell         return do_3same_pair(s, a, fns[a->size]);                       \
997059c2398SPeter Maydell     }
998059c2398SPeter Maydell 
999059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions.  */
1000059c2398SPeter Maydell #define gen_helper_neon_pmax_s32  tcg_gen_smax_i32
1001059c2398SPeter Maydell #define gen_helper_neon_pmax_u32  tcg_gen_umax_i32
1002059c2398SPeter Maydell #define gen_helper_neon_pmin_s32  tcg_gen_smin_i32
1003059c2398SPeter Maydell #define gen_helper_neon_pmin_u32  tcg_gen_umin_i32
1004fa22827dSPeter Maydell #define gen_helper_neon_padd_u32  tcg_gen_add_i32
1005059c2398SPeter Maydell 
1006059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s)
1007059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s)
1008059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u)
1009059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u)
1010fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u)
10117ecc28bcSPeter Maydell 
10127ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC)                                    \
10137ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16);    \
10147ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32);    \
10157ecc28bcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
10167ecc28bcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
10177ecc28bcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
10187ecc28bcSPeter Maydell     {                                                                   \
10197ecc28bcSPeter Maydell         static const GVecGen3 ops[2] = {                                \
10207ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
10217ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
10227ecc28bcSPeter Maydell         };                                                              \
10237ecc28bcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \
10247ecc28bcSPeter Maydell     }                                                                   \
10257ecc28bcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
10267ecc28bcSPeter Maydell     {                                                                   \
10277ecc28bcSPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
10287ecc28bcSPeter Maydell             return false;                                               \
10297ecc28bcSPeter Maydell         }                                                               \
10307ecc28bcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
10317ecc28bcSPeter Maydell     }
10327ecc28bcSPeter Maydell 
10337ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh)
10347ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh)
1035a26a352bSPeter Maydell 
10368aa71eadSPeter Maydell static bool do_3same_fp(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn,
10378aa71eadSPeter Maydell                         bool reads_vd)
10388aa71eadSPeter Maydell {
10398aa71eadSPeter Maydell     /*
10408aa71eadSPeter Maydell      * FP operations handled elementwise 32 bits at a time.
10418aa71eadSPeter Maydell      * If reads_vd is true then the old value of Vd will be
10428aa71eadSPeter Maydell      * loaded before calling the callback function. This is
10438aa71eadSPeter Maydell      * used for multiply-accumulate type operations.
10448aa71eadSPeter Maydell      */
10458aa71eadSPeter Maydell     TCGv_i32 tmp, tmp2;
10468aa71eadSPeter Maydell     int pass;
10478aa71eadSPeter Maydell 
10488aa71eadSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
10498aa71eadSPeter Maydell         return false;
10508aa71eadSPeter Maydell     }
10518aa71eadSPeter Maydell 
10528aa71eadSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
10538aa71eadSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
10548aa71eadSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
10558aa71eadSPeter Maydell         return false;
10568aa71eadSPeter Maydell     }
10578aa71eadSPeter Maydell 
10588aa71eadSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
10598aa71eadSPeter Maydell         return false;
10608aa71eadSPeter Maydell     }
10618aa71eadSPeter Maydell 
10628aa71eadSPeter Maydell     if (!vfp_access_check(s)) {
10638aa71eadSPeter Maydell         return true;
10648aa71eadSPeter Maydell     }
10658aa71eadSPeter Maydell 
1066a84d1d13SPeter Maydell     TCGv_ptr fpstatus = fpstatus_ptr(FPST_STD);
10678aa71eadSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
10688aa71eadSPeter Maydell         tmp = neon_load_reg(a->vn, pass);
10698aa71eadSPeter Maydell         tmp2 = neon_load_reg(a->vm, pass);
10708aa71eadSPeter Maydell         if (reads_vd) {
10718aa71eadSPeter Maydell             TCGv_i32 tmp_rd = neon_load_reg(a->vd, pass);
10728aa71eadSPeter Maydell             fn(tmp_rd, tmp, tmp2, fpstatus);
10738aa71eadSPeter Maydell             neon_store_reg(a->vd, pass, tmp_rd);
10748aa71eadSPeter Maydell             tcg_temp_free_i32(tmp);
10758aa71eadSPeter Maydell         } else {
10768aa71eadSPeter Maydell             fn(tmp, tmp, tmp2, fpstatus);
10778aa71eadSPeter Maydell             neon_store_reg(a->vd, pass, tmp);
10788aa71eadSPeter Maydell         }
10798aa71eadSPeter Maydell         tcg_temp_free_i32(tmp2);
10808aa71eadSPeter Maydell     }
10818aa71eadSPeter Maydell     tcg_temp_free_ptr(fpstatus);
10828aa71eadSPeter Maydell     return true;
10838aa71eadSPeter Maydell }
10848aa71eadSPeter Maydell 
1085*e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC)                              \
1086*e4a6d4a6SPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
1087a26a352bSPeter Maydell                          uint32_t rn_ofs, uint32_t rm_ofs,              \
1088a26a352bSPeter Maydell                          uint32_t oprsz, uint32_t maxsz)                \
1089a26a352bSPeter Maydell     {                                                                   \
1090*e4a6d4a6SPeter Maydell         TCGv_ptr fpst = fpstatus_ptr(FPST);                             \
1091a26a352bSPeter Maydell         tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst,                \
1092a26a352bSPeter Maydell                            oprsz, maxsz, 0, FUNC);                      \
1093a26a352bSPeter Maydell         tcg_temp_free_ptr(fpst);                                        \
1094*e4a6d4a6SPeter Maydell     }
1095*e4a6d4a6SPeter Maydell 
1096*e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC)                                 \
1097*e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC)                 \
1098*e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC)             \
1099a26a352bSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a)     \
1100a26a352bSPeter Maydell     {                                                                   \
1101a26a352bSPeter Maydell         if (a->size != 0) {                                             \
1102*e4a6d4a6SPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
1103a26a352bSPeter Maydell                 return false;                                           \
1104a26a352bSPeter Maydell             }                                                           \
1105*e4a6d4a6SPeter Maydell             return do_3same(s, a, gen_##INSN##_fp16_3s);                \
1106*e4a6d4a6SPeter Maydell         }                                                               \
1107*e4a6d4a6SPeter Maydell         return do_3same(s, a, gen_##INSN##_fp32_3s);                    \
1108a26a352bSPeter Maydell     }
1109a26a352bSPeter Maydell 
1110a26a352bSPeter Maydell 
1111*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h)
1112*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h)
1113*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h)
1114*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h)
11158aa71eadSPeter Maydell 
11168aa71eadSPeter Maydell /*
11178aa71eadSPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
11188aa71eadSPeter Maydell  * which is an architecture extension we don't implement yet.
11198aa71eadSPeter Maydell  */
11208aa71eadSPeter Maydell #define DO_3S_FP(INSN,FUNC,READS_VD)                                \
11218aa71eadSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \
11228aa71eadSPeter Maydell     {                                                               \
11238aa71eadSPeter Maydell         if (a->size != 0) {                                         \
11248aa71eadSPeter Maydell             /* TODO fp16 support */                                 \
11258aa71eadSPeter Maydell             return false;                                           \
11268aa71eadSPeter Maydell         }                                                           \
11278aa71eadSPeter Maydell         return do_3same_fp(s, a, FUNC, READS_VD);                   \
11288aa71eadSPeter Maydell     }
11298aa71eadSPeter Maydell 
1130727ff1d6SPeter Maydell DO_3S_FP(VCEQ, gen_helper_neon_ceq_f32, false)
1131727ff1d6SPeter Maydell DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false)
1132727ff1d6SPeter Maydell DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false)
1133727ff1d6SPeter Maydell DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false)
1134727ff1d6SPeter Maydell DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false)
1135d5fdf9e9SPeter Maydell DO_3S_FP(VMAX, gen_helper_vfp_maxs, false)
1136d5fdf9e9SPeter Maydell DO_3S_FP(VMIN, gen_helper_vfp_mins, false)
1137727ff1d6SPeter Maydell 
11388aa71eadSPeter Maydell static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
11398aa71eadSPeter Maydell                             TCGv_ptr fpstatus)
11408aa71eadSPeter Maydell {
11418aa71eadSPeter Maydell     gen_helper_vfp_muls(vn, vn, vm, fpstatus);
11428aa71eadSPeter Maydell     gen_helper_vfp_adds(vd, vd, vn, fpstatus);
11438aa71eadSPeter Maydell }
11448aa71eadSPeter Maydell 
11458aa71eadSPeter Maydell static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
11468aa71eadSPeter Maydell                             TCGv_ptr fpstatus)
11478aa71eadSPeter Maydell {
11488aa71eadSPeter Maydell     gen_helper_vfp_muls(vn, vn, vm, fpstatus);
11498aa71eadSPeter Maydell     gen_helper_vfp_subs(vd, vd, vn, fpstatus);
11508aa71eadSPeter Maydell }
11518aa71eadSPeter Maydell 
11528aa71eadSPeter Maydell DO_3S_FP(VMLA, gen_VMLA_fp_3s, true)
11538aa71eadSPeter Maydell DO_3S_FP(VMLS, gen_VMLS_fp_3s, true)
1154ab978335SPeter Maydell 
1155d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a)
1156d5fdf9e9SPeter Maydell {
1157d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1158d5fdf9e9SPeter Maydell         return false;
1159d5fdf9e9SPeter Maydell     }
1160d5fdf9e9SPeter Maydell 
1161d5fdf9e9SPeter Maydell     if (a->size != 0) {
1162d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1163d5fdf9e9SPeter Maydell         return false;
1164d5fdf9e9SPeter Maydell     }
1165d5fdf9e9SPeter Maydell 
1166d5fdf9e9SPeter Maydell     return do_3same_fp(s, a, gen_helper_vfp_maxnums, false);
1167d5fdf9e9SPeter Maydell }
1168d5fdf9e9SPeter Maydell 
1169d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a)
1170d5fdf9e9SPeter Maydell {
1171d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1172d5fdf9e9SPeter Maydell         return false;
1173d5fdf9e9SPeter Maydell     }
1174d5fdf9e9SPeter Maydell 
1175d5fdf9e9SPeter Maydell     if (a->size != 0) {
1176d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1177d5fdf9e9SPeter Maydell         return false;
1178d5fdf9e9SPeter Maydell     }
1179d5fdf9e9SPeter Maydell 
1180d5fdf9e9SPeter Maydell     return do_3same_fp(s, a, gen_helper_vfp_minnums, false);
1181d5fdf9e9SPeter Maydell }
1182d5fdf9e9SPeter Maydell 
1183d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRECPS_tramp, gen_helper_recps_f32)
1184d5fdf9e9SPeter Maydell 
1185d5fdf9e9SPeter Maydell static void gen_VRECPS_fp_3s(unsigned vece, uint32_t rd_ofs,
1186d5fdf9e9SPeter Maydell                              uint32_t rn_ofs, uint32_t rm_ofs,
1187d5fdf9e9SPeter Maydell                              uint32_t oprsz, uint32_t maxsz)
1188d5fdf9e9SPeter Maydell {
1189d5fdf9e9SPeter Maydell     static const GVecGen3 ops = { .fni4 = gen_VRECPS_tramp };
1190d5fdf9e9SPeter Maydell     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops);
1191d5fdf9e9SPeter Maydell }
1192d5fdf9e9SPeter Maydell 
1193d5fdf9e9SPeter Maydell static bool trans_VRECPS_fp_3s(DisasContext *s, arg_3same *a)
1194d5fdf9e9SPeter Maydell {
1195d5fdf9e9SPeter Maydell     if (a->size != 0) {
1196d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1197d5fdf9e9SPeter Maydell         return false;
1198d5fdf9e9SPeter Maydell     }
1199d5fdf9e9SPeter Maydell 
1200d5fdf9e9SPeter Maydell     return do_3same(s, a, gen_VRECPS_fp_3s);
1201d5fdf9e9SPeter Maydell }
1202d5fdf9e9SPeter Maydell 
1203d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRSQRTS_tramp, gen_helper_rsqrts_f32)
1204d5fdf9e9SPeter Maydell 
1205d5fdf9e9SPeter Maydell static void gen_VRSQRTS_fp_3s(unsigned vece, uint32_t rd_ofs,
1206d5fdf9e9SPeter Maydell                               uint32_t rn_ofs, uint32_t rm_ofs,
1207d5fdf9e9SPeter Maydell                               uint32_t oprsz, uint32_t maxsz)
1208d5fdf9e9SPeter Maydell {
1209d5fdf9e9SPeter Maydell     static const GVecGen3 ops = { .fni4 = gen_VRSQRTS_tramp };
1210d5fdf9e9SPeter Maydell     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops);
1211d5fdf9e9SPeter Maydell }
1212d5fdf9e9SPeter Maydell 
1213d5fdf9e9SPeter Maydell static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a)
1214d5fdf9e9SPeter Maydell {
1215d5fdf9e9SPeter Maydell     if (a->size != 0) {
1216d5fdf9e9SPeter Maydell         /* TODO fp16 support */
1217d5fdf9e9SPeter Maydell         return false;
1218d5fdf9e9SPeter Maydell     }
1219d5fdf9e9SPeter Maydell 
1220d5fdf9e9SPeter Maydell     return do_3same(s, a, gen_VRSQRTS_fp_3s);
1221d5fdf9e9SPeter Maydell }
1222d5fdf9e9SPeter Maydell 
1223e95485f8SPeter Maydell static void gen_VFMA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
1224e95485f8SPeter Maydell                             TCGv_ptr fpstatus)
1225e95485f8SPeter Maydell {
1226e95485f8SPeter Maydell     gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus);
1227e95485f8SPeter Maydell }
1228e95485f8SPeter Maydell 
1229e95485f8SPeter Maydell static bool trans_VFMA_fp_3s(DisasContext *s, arg_3same *a)
1230e95485f8SPeter Maydell {
1231e95485f8SPeter Maydell     if (!dc_isar_feature(aa32_simdfmac, s)) {
1232e95485f8SPeter Maydell         return false;
1233e95485f8SPeter Maydell     }
1234e95485f8SPeter Maydell 
1235e95485f8SPeter Maydell     if (a->size != 0) {
1236e95485f8SPeter Maydell         /* TODO fp16 support */
1237e95485f8SPeter Maydell         return false;
1238e95485f8SPeter Maydell     }
1239e95485f8SPeter Maydell 
1240e95485f8SPeter Maydell     return do_3same_fp(s, a, gen_VFMA_fp_3s, true);
1241e95485f8SPeter Maydell }
1242e95485f8SPeter Maydell 
1243e95485f8SPeter Maydell static void gen_VFMS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm,
1244e95485f8SPeter Maydell                             TCGv_ptr fpstatus)
1245e95485f8SPeter Maydell {
1246e95485f8SPeter Maydell     gen_helper_vfp_negs(vn, vn);
1247e95485f8SPeter Maydell     gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus);
1248e95485f8SPeter Maydell }
1249e95485f8SPeter Maydell 
1250e95485f8SPeter Maydell static bool trans_VFMS_fp_3s(DisasContext *s, arg_3same *a)
1251e95485f8SPeter Maydell {
1252e95485f8SPeter Maydell     if (!dc_isar_feature(aa32_simdfmac, s)) {
1253e95485f8SPeter Maydell         return false;
1254e95485f8SPeter Maydell     }
1255e95485f8SPeter Maydell 
1256e95485f8SPeter Maydell     if (a->size != 0) {
1257e95485f8SPeter Maydell         /* TODO fp16 support */
1258e95485f8SPeter Maydell         return false;
1259e95485f8SPeter Maydell     }
1260e95485f8SPeter Maydell 
1261e95485f8SPeter Maydell     return do_3same_fp(s, a, gen_VFMS_fp_3s, true);
1262e95485f8SPeter Maydell }
1263e95485f8SPeter Maydell 
1264ab978335SPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn)
1265ab978335SPeter Maydell {
1266ab978335SPeter Maydell     /* FP operations handled pairwise 32 bits at a time */
1267ab978335SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3;
1268ab978335SPeter Maydell     TCGv_ptr fpstatus;
1269ab978335SPeter Maydell 
1270ab978335SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1271ab978335SPeter Maydell         return false;
1272ab978335SPeter Maydell     }
1273ab978335SPeter Maydell 
1274ab978335SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1275ab978335SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1276ab978335SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1277ab978335SPeter Maydell         return false;
1278ab978335SPeter Maydell     }
1279ab978335SPeter Maydell 
1280ab978335SPeter Maydell     if (!vfp_access_check(s)) {
1281ab978335SPeter Maydell         return true;
1282ab978335SPeter Maydell     }
1283ab978335SPeter Maydell 
1284ab978335SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
1285ab978335SPeter Maydell 
1286ab978335SPeter Maydell     /*
1287ab978335SPeter Maydell      * Note that we have to be careful not to clobber the source operands
1288ab978335SPeter Maydell      * in the "vm == vd" case by storing the result of the first pass too
1289ab978335SPeter Maydell      * early. Since Q is 0 there are always just two passes, so instead
1290ab978335SPeter Maydell      * of a complicated loop over each pass we just unroll.
1291ab978335SPeter Maydell      */
1292a84d1d13SPeter Maydell     fpstatus = fpstatus_ptr(FPST_STD);
1293ab978335SPeter Maydell     tmp = neon_load_reg(a->vn, 0);
1294ab978335SPeter Maydell     tmp2 = neon_load_reg(a->vn, 1);
1295ab978335SPeter Maydell     fn(tmp, tmp, tmp2, fpstatus);
1296ab978335SPeter Maydell     tcg_temp_free_i32(tmp2);
1297ab978335SPeter Maydell 
1298ab978335SPeter Maydell     tmp3 = neon_load_reg(a->vm, 0);
1299ab978335SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
1300ab978335SPeter Maydell     fn(tmp3, tmp3, tmp2, fpstatus);
1301ab978335SPeter Maydell     tcg_temp_free_i32(tmp2);
1302ab978335SPeter Maydell     tcg_temp_free_ptr(fpstatus);
1303ab978335SPeter Maydell 
1304ab978335SPeter Maydell     neon_store_reg(a->vd, 0, tmp);
1305ab978335SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
1306ab978335SPeter Maydell     return true;
1307ab978335SPeter Maydell }
1308ab978335SPeter Maydell 
1309ab978335SPeter Maydell /*
1310ab978335SPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
1311ab978335SPeter Maydell  * which is an architecture extension we don't implement yet.
1312ab978335SPeter Maydell  */
1313ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC)                                    \
1314ab978335SPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \
1315ab978335SPeter Maydell     {                                                               \
1316ab978335SPeter Maydell         if (a->size != 0) {                                         \
1317ab978335SPeter Maydell             /* TODO fp16 support */                                 \
1318ab978335SPeter Maydell             return false;                                           \
1319ab978335SPeter Maydell         }                                                           \
1320ab978335SPeter Maydell         return do_3same_fp_pair(s, a, FUNC);                        \
1321ab978335SPeter Maydell     }
1322ab978335SPeter Maydell 
1323ab978335SPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds)
1324ab978335SPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs)
1325ab978335SPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins)
1326d3c8c736SPeter Maydell 
1327d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
1328d3c8c736SPeter Maydell {
1329d3c8c736SPeter Maydell     /* Handle a 2-reg-shift insn which can be vectorized. */
1330d3c8c736SPeter Maydell     int vec_size = a->q ? 16 : 8;
1331d3c8c736SPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
1332d3c8c736SPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
1333d3c8c736SPeter Maydell 
1334d3c8c736SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1335d3c8c736SPeter Maydell         return false;
1336d3c8c736SPeter Maydell     }
1337d3c8c736SPeter Maydell 
1338d3c8c736SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1339d3c8c736SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1340d3c8c736SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1341d3c8c736SPeter Maydell         return false;
1342d3c8c736SPeter Maydell     }
1343d3c8c736SPeter Maydell 
1344d3c8c736SPeter Maydell     if ((a->vm | a->vd) & a->q) {
1345d3c8c736SPeter Maydell         return false;
1346d3c8c736SPeter Maydell     }
1347d3c8c736SPeter Maydell 
1348d3c8c736SPeter Maydell     if (!vfp_access_check(s)) {
1349d3c8c736SPeter Maydell         return true;
1350d3c8c736SPeter Maydell     }
1351d3c8c736SPeter Maydell 
1352d3c8c736SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size);
1353d3c8c736SPeter Maydell     return true;
1354d3c8c736SPeter Maydell }
1355d3c8c736SPeter Maydell 
1356d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC)                                              \
1357d3c8c736SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1358d3c8c736SPeter Maydell     {                                                                   \
1359d3c8c736SPeter Maydell         return do_vector_2sh(s, a, FUNC);                               \
1360d3c8c736SPeter Maydell     }                                                                   \
1361d3c8c736SPeter Maydell 
1362d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli)
1363d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli)
1364434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri)
1365434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra)
1366434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra)
1367434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr)
1368434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr)
1369434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra)
1370434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra)
137166432d6bSPeter Maydell 
137266432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a)
137366432d6bSPeter Maydell {
137466432d6bSPeter Maydell     /* Signed shift out of range results in all-sign-bits */
137566432d6bSPeter Maydell     a->shift = MIN(a->shift, (8 << a->size) - 1);
137666432d6bSPeter Maydell     return do_vector_2sh(s, a, tcg_gen_gvec_sari);
137766432d6bSPeter Maydell }
137866432d6bSPeter Maydell 
137966432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
138066432d6bSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
138166432d6bSPeter Maydell {
138266432d6bSPeter Maydell     tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0);
138366432d6bSPeter Maydell }
138466432d6bSPeter Maydell 
138566432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a)
138666432d6bSPeter Maydell {
138766432d6bSPeter Maydell     /* Shift out of range is architecturally valid and results in zero. */
138866432d6bSPeter Maydell     if (a->shift >= (8 << a->size)) {
138966432d6bSPeter Maydell         return do_vector_2sh(s, a, gen_zero_rd_2sh);
139066432d6bSPeter Maydell     } else {
139166432d6bSPeter Maydell         return do_vector_2sh(s, a, tcg_gen_gvec_shri);
139266432d6bSPeter Maydell     }
139366432d6bSPeter Maydell }
139437bfce81SPeter Maydell 
139537bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a,
139637bfce81SPeter Maydell                              NeonGenTwo64OpEnvFn *fn)
139737bfce81SPeter Maydell {
139837bfce81SPeter Maydell     /*
139937bfce81SPeter Maydell      * 2-reg-and-shift operations, size == 3 case, where the
140037bfce81SPeter Maydell      * function needs to be passed cpu_env.
140137bfce81SPeter Maydell      */
140237bfce81SPeter Maydell     TCGv_i64 constimm;
140337bfce81SPeter Maydell     int pass;
140437bfce81SPeter Maydell 
140537bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
140637bfce81SPeter Maydell         return false;
140737bfce81SPeter Maydell     }
140837bfce81SPeter Maydell 
140937bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
141037bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
141137bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
141237bfce81SPeter Maydell         return false;
141337bfce81SPeter Maydell     }
141437bfce81SPeter Maydell 
141537bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
141637bfce81SPeter Maydell         return false;
141737bfce81SPeter Maydell     }
141837bfce81SPeter Maydell 
141937bfce81SPeter Maydell     if (!vfp_access_check(s)) {
142037bfce81SPeter Maydell         return true;
142137bfce81SPeter Maydell     }
142237bfce81SPeter Maydell 
142337bfce81SPeter Maydell     /*
142437bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
142537bfce81SPeter Maydell      * by immediate using the variable shift operations.
142637bfce81SPeter Maydell      */
142737bfce81SPeter Maydell     constimm = tcg_const_i64(dup_const(a->size, a->shift));
142837bfce81SPeter Maydell 
142937bfce81SPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
143037bfce81SPeter Maydell         TCGv_i64 tmp = tcg_temp_new_i64();
143137bfce81SPeter Maydell 
143237bfce81SPeter Maydell         neon_load_reg64(tmp, a->vm + pass);
143337bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
143437bfce81SPeter Maydell         neon_store_reg64(tmp, a->vd + pass);
1435a4f67e18SPeter Maydell         tcg_temp_free_i64(tmp);
143637bfce81SPeter Maydell     }
143737bfce81SPeter Maydell     tcg_temp_free_i64(constimm);
143837bfce81SPeter Maydell     return true;
143937bfce81SPeter Maydell }
144037bfce81SPeter Maydell 
144137bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a,
144237bfce81SPeter Maydell                              NeonGenTwoOpEnvFn *fn)
144337bfce81SPeter Maydell {
144437bfce81SPeter Maydell     /*
144537bfce81SPeter Maydell      * 2-reg-and-shift operations, size < 3 case, where the
144637bfce81SPeter Maydell      * helper needs to be passed cpu_env.
144737bfce81SPeter Maydell      */
144837bfce81SPeter Maydell     TCGv_i32 constimm;
144937bfce81SPeter Maydell     int pass;
145037bfce81SPeter Maydell 
145137bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
145237bfce81SPeter Maydell         return false;
145337bfce81SPeter Maydell     }
145437bfce81SPeter Maydell 
145537bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
145637bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
145737bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
145837bfce81SPeter Maydell         return false;
145937bfce81SPeter Maydell     }
146037bfce81SPeter Maydell 
146137bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
146237bfce81SPeter Maydell         return false;
146337bfce81SPeter Maydell     }
146437bfce81SPeter Maydell 
146537bfce81SPeter Maydell     if (!vfp_access_check(s)) {
146637bfce81SPeter Maydell         return true;
146737bfce81SPeter Maydell     }
146837bfce81SPeter Maydell 
146937bfce81SPeter Maydell     /*
147037bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
147137bfce81SPeter Maydell      * by immediate using the variable shift operations.
147237bfce81SPeter Maydell      */
147337bfce81SPeter Maydell     constimm = tcg_const_i32(dup_const(a->size, a->shift));
147437bfce81SPeter Maydell 
147537bfce81SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
147637bfce81SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
147737bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
147837bfce81SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
147937bfce81SPeter Maydell     }
148037bfce81SPeter Maydell     tcg_temp_free_i32(constimm);
148137bfce81SPeter Maydell     return true;
148237bfce81SPeter Maydell }
148337bfce81SPeter Maydell 
148437bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC)                                       \
148537bfce81SPeter Maydell     static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \
148637bfce81SPeter Maydell     {                                                                   \
148737bfce81SPeter Maydell         return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64);      \
148837bfce81SPeter Maydell     }                                                                   \
148937bfce81SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
149037bfce81SPeter Maydell     {                                                                   \
149137bfce81SPeter Maydell         static NeonGenTwoOpEnvFn * const fns[] = {                      \
149237bfce81SPeter Maydell             gen_helper_neon_##FUNC##8,                                  \
149337bfce81SPeter Maydell             gen_helper_neon_##FUNC##16,                                 \
149437bfce81SPeter Maydell             gen_helper_neon_##FUNC##32,                                 \
149537bfce81SPeter Maydell         };                                                              \
149637bfce81SPeter Maydell         assert(a->size < ARRAY_SIZE(fns));                              \
149737bfce81SPeter Maydell         return do_2shift_env_32(s, a, fns[a->size]);                    \
149837bfce81SPeter Maydell     }
149937bfce81SPeter Maydell 
150037bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s)
150137bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u)
150237bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s)
1503712182d3SPeter Maydell 
1504712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
1505712182d3SPeter Maydell                                 NeonGenTwo64OpFn *shiftfn,
1506712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1507712182d3SPeter Maydell {
1508712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size == 3 case */
1509712182d3SPeter Maydell     TCGv_i64 constimm, rm1, rm2;
1510712182d3SPeter Maydell     TCGv_i32 rd;
1511712182d3SPeter Maydell 
1512712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1513712182d3SPeter Maydell         return false;
1514712182d3SPeter Maydell     }
1515712182d3SPeter Maydell 
1516712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1517712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1518712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1519712182d3SPeter Maydell         return false;
1520712182d3SPeter Maydell     }
1521712182d3SPeter Maydell 
1522712182d3SPeter Maydell     if (a->vm & 1) {
1523712182d3SPeter Maydell         return false;
1524712182d3SPeter Maydell     }
1525712182d3SPeter Maydell 
1526712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1527712182d3SPeter Maydell         return true;
1528712182d3SPeter Maydell     }
1529712182d3SPeter Maydell 
1530712182d3SPeter Maydell     /*
1531712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1532712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count.
1533712182d3SPeter Maydell      */
1534712182d3SPeter Maydell     constimm = tcg_const_i64(-a->shift);
1535712182d3SPeter Maydell     rm1 = tcg_temp_new_i64();
1536712182d3SPeter Maydell     rm2 = tcg_temp_new_i64();
1537712182d3SPeter Maydell 
1538712182d3SPeter Maydell     /* Load both inputs first to avoid potential overwrite if rm == rd */
1539712182d3SPeter Maydell     neon_load_reg64(rm1, a->vm);
1540712182d3SPeter Maydell     neon_load_reg64(rm2, a->vm + 1);
1541712182d3SPeter Maydell 
1542712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1543712182d3SPeter Maydell     rd = tcg_temp_new_i32();
1544712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm1);
1545712182d3SPeter Maydell     neon_store_reg(a->vd, 0, rd);
1546712182d3SPeter Maydell 
1547712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1548712182d3SPeter Maydell     rd = tcg_temp_new_i32();
1549712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm2);
1550712182d3SPeter Maydell     neon_store_reg(a->vd, 1, rd);
1551712182d3SPeter Maydell 
1552712182d3SPeter Maydell     tcg_temp_free_i64(rm1);
1553712182d3SPeter Maydell     tcg_temp_free_i64(rm2);
1554712182d3SPeter Maydell     tcg_temp_free_i64(constimm);
1555712182d3SPeter Maydell 
1556712182d3SPeter Maydell     return true;
1557712182d3SPeter Maydell }
1558712182d3SPeter Maydell 
1559712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
1560712182d3SPeter Maydell                                 NeonGenTwoOpFn *shiftfn,
1561712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1562712182d3SPeter Maydell {
1563712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size < 3 case */
1564712182d3SPeter Maydell     TCGv_i32 constimm, rm1, rm2, rm3, rm4;
1565712182d3SPeter Maydell     TCGv_i64 rtmp;
1566712182d3SPeter Maydell     uint32_t imm;
1567712182d3SPeter Maydell 
1568712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1569712182d3SPeter Maydell         return false;
1570712182d3SPeter Maydell     }
1571712182d3SPeter Maydell 
1572712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1573712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1574712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1575712182d3SPeter Maydell         return false;
1576712182d3SPeter Maydell     }
1577712182d3SPeter Maydell 
1578712182d3SPeter Maydell     if (a->vm & 1) {
1579712182d3SPeter Maydell         return false;
1580712182d3SPeter Maydell     }
1581712182d3SPeter Maydell 
1582712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1583712182d3SPeter Maydell         return true;
1584712182d3SPeter Maydell     }
1585712182d3SPeter Maydell 
1586712182d3SPeter Maydell     /*
1587712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1588712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count
1589712182d3SPeter Maydell      * duplicated into each lane of the immediate value.
1590712182d3SPeter Maydell      */
1591712182d3SPeter Maydell     if (a->size == 1) {
1592712182d3SPeter Maydell         imm = (uint16_t)(-a->shift);
1593712182d3SPeter Maydell         imm |= imm << 16;
1594712182d3SPeter Maydell     } else {
1595712182d3SPeter Maydell         /* size == 2 */
1596712182d3SPeter Maydell         imm = -a->shift;
1597712182d3SPeter Maydell     }
1598712182d3SPeter Maydell     constimm = tcg_const_i32(imm);
1599712182d3SPeter Maydell 
1600712182d3SPeter Maydell     /* Load all inputs first to avoid potential overwrite */
1601712182d3SPeter Maydell     rm1 = neon_load_reg(a->vm, 0);
1602712182d3SPeter Maydell     rm2 = neon_load_reg(a->vm, 1);
1603712182d3SPeter Maydell     rm3 = neon_load_reg(a->vm + 1, 0);
1604712182d3SPeter Maydell     rm4 = neon_load_reg(a->vm + 1, 1);
1605712182d3SPeter Maydell     rtmp = tcg_temp_new_i64();
1606712182d3SPeter Maydell 
1607712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1608712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1609712182d3SPeter Maydell 
1610712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
1611712182d3SPeter Maydell     tcg_temp_free_i32(rm2);
1612712182d3SPeter Maydell 
1613712182d3SPeter Maydell     narrowfn(rm1, cpu_env, rtmp);
1614712182d3SPeter Maydell     neon_store_reg(a->vd, 0, rm1);
1615712182d3SPeter Maydell 
1616712182d3SPeter Maydell     shiftfn(rm3, rm3, constimm);
1617712182d3SPeter Maydell     shiftfn(rm4, rm4, constimm);
1618712182d3SPeter Maydell     tcg_temp_free_i32(constimm);
1619712182d3SPeter Maydell 
1620712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
1621712182d3SPeter Maydell     tcg_temp_free_i32(rm4);
1622712182d3SPeter Maydell 
1623712182d3SPeter Maydell     narrowfn(rm3, cpu_env, rtmp);
1624712182d3SPeter Maydell     tcg_temp_free_i64(rtmp);
1625712182d3SPeter Maydell     neon_store_reg(a->vd, 1, rm3);
1626712182d3SPeter Maydell     return true;
1627712182d3SPeter Maydell }
1628712182d3SPeter Maydell 
1629712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC)                               \
1630712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1631712182d3SPeter Maydell     {                                                                   \
1632712182d3SPeter Maydell         return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC);             \
1633712182d3SPeter Maydell     }
1634712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC)                               \
1635712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1636712182d3SPeter Maydell     {                                                                   \
1637712182d3SPeter Maydell         return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC);             \
1638712182d3SPeter Maydell     }
1639712182d3SPeter Maydell 
1640712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1641712182d3SPeter Maydell {
1642712182d3SPeter Maydell     tcg_gen_extrl_i64_i32(dest, src);
1643712182d3SPeter Maydell }
1644712182d3SPeter Maydell 
1645712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1646712182d3SPeter Maydell {
1647712182d3SPeter Maydell     gen_helper_neon_narrow_u16(dest, src);
1648712182d3SPeter Maydell }
1649712182d3SPeter Maydell 
1650712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1651712182d3SPeter Maydell {
1652712182d3SPeter Maydell     gen_helper_neon_narrow_u8(dest, src);
1653712182d3SPeter Maydell }
1654712182d3SPeter Maydell 
1655712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32)
1656712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16)
1657712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8)
1658712182d3SPeter Maydell 
1659712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32)
1660712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16)
1661712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8)
1662712182d3SPeter Maydell 
1663712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32)
1664712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16)
1665712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8)
1666712182d3SPeter Maydell 
1667712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32)
1668712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16)
1669712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8)
1670b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32)
1671b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16)
1672b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8)
1673b4a3a77bSPeter Maydell 
1674b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32)
1675b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16)
1676b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8)
1677b4a3a77bSPeter Maydell 
1678b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32)
1679b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16)
1680b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8)
1681b4a3a77bSPeter Maydell 
1682b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32)
1683b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16)
1684b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8)
1685968bf842SPeter Maydell 
1686968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
1687968bf842SPeter Maydell                          NeonGenWidenFn *widenfn, bool u)
1688968bf842SPeter Maydell {
1689968bf842SPeter Maydell     TCGv_i64 tmp;
1690968bf842SPeter Maydell     TCGv_i32 rm0, rm1;
1691968bf842SPeter Maydell     uint64_t widen_mask = 0;
1692968bf842SPeter Maydell 
1693968bf842SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1694968bf842SPeter Maydell         return false;
1695968bf842SPeter Maydell     }
1696968bf842SPeter Maydell 
1697968bf842SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1698968bf842SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1699968bf842SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1700968bf842SPeter Maydell         return false;
1701968bf842SPeter Maydell     }
1702968bf842SPeter Maydell 
1703968bf842SPeter Maydell     if (a->vd & 1) {
1704968bf842SPeter Maydell         return false;
1705968bf842SPeter Maydell     }
1706968bf842SPeter Maydell 
1707968bf842SPeter Maydell     if (!vfp_access_check(s)) {
1708968bf842SPeter Maydell         return true;
1709968bf842SPeter Maydell     }
1710968bf842SPeter Maydell 
1711968bf842SPeter Maydell     /*
1712968bf842SPeter Maydell      * This is a widen-and-shift operation. The shift is always less
1713968bf842SPeter Maydell      * than the width of the source type, so after widening the input
1714968bf842SPeter Maydell      * vector we can simply shift the whole 64-bit widened register,
1715968bf842SPeter Maydell      * and then clear the potential overflow bits resulting from left
1716968bf842SPeter Maydell      * bits of the narrow input appearing as right bits of the left
1717968bf842SPeter Maydell      * neighbour narrow input. Calculate a mask of bits to clear.
1718968bf842SPeter Maydell      */
1719968bf842SPeter Maydell     if ((a->shift != 0) && (a->size < 2 || u)) {
1720968bf842SPeter Maydell         int esize = 8 << a->size;
1721968bf842SPeter Maydell         widen_mask = MAKE_64BIT_MASK(0, esize);
1722968bf842SPeter Maydell         widen_mask >>= esize - a->shift;
1723968bf842SPeter Maydell         widen_mask = dup_const(a->size + 1, widen_mask);
1724968bf842SPeter Maydell     }
1725968bf842SPeter Maydell 
1726968bf842SPeter Maydell     rm0 = neon_load_reg(a->vm, 0);
1727968bf842SPeter Maydell     rm1 = neon_load_reg(a->vm, 1);
1728968bf842SPeter Maydell     tmp = tcg_temp_new_i64();
1729968bf842SPeter Maydell 
1730968bf842SPeter Maydell     widenfn(tmp, rm0);
17319593a398SPeter Maydell     tcg_temp_free_i32(rm0);
1732968bf842SPeter Maydell     if (a->shift != 0) {
1733968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1734968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1735968bf842SPeter Maydell     }
1736968bf842SPeter Maydell     neon_store_reg64(tmp, a->vd);
1737968bf842SPeter Maydell 
1738968bf842SPeter Maydell     widenfn(tmp, rm1);
17399593a398SPeter Maydell     tcg_temp_free_i32(rm1);
1740968bf842SPeter Maydell     if (a->shift != 0) {
1741968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1742968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1743968bf842SPeter Maydell     }
1744968bf842SPeter Maydell     neon_store_reg64(tmp, a->vd + 1);
1745968bf842SPeter Maydell     tcg_temp_free_i64(tmp);
1746968bf842SPeter Maydell     return true;
1747968bf842SPeter Maydell }
1748968bf842SPeter Maydell 
1749968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a)
1750968bf842SPeter Maydell {
1751448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1752968bf842SPeter Maydell         gen_helper_neon_widen_s8,
1753968bf842SPeter Maydell         gen_helper_neon_widen_s16,
1754968bf842SPeter Maydell         tcg_gen_ext_i32_i64,
1755968bf842SPeter Maydell     };
1756968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], false);
1757968bf842SPeter Maydell }
1758968bf842SPeter Maydell 
1759968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
1760968bf842SPeter Maydell {
1761448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1762968bf842SPeter Maydell         gen_helper_neon_widen_u8,
1763968bf842SPeter Maydell         gen_helper_neon_widen_u16,
1764968bf842SPeter Maydell         tcg_gen_extu_i32_i64,
1765968bf842SPeter Maydell     };
1766968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], true);
1767968bf842SPeter Maydell }
17683da26f11SPeter Maydell 
17693da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
17705de3fd04SPeter Maydell                       NeonGenTwoSingleOpFn *fn)
17713da26f11SPeter Maydell {
17723da26f11SPeter Maydell     /* FP operations in 2-reg-and-shift group */
17733da26f11SPeter Maydell     TCGv_i32 tmp, shiftv;
17743da26f11SPeter Maydell     TCGv_ptr fpstatus;
17753da26f11SPeter Maydell     int pass;
17763da26f11SPeter Maydell 
17773da26f11SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
17783da26f11SPeter Maydell         return false;
17793da26f11SPeter Maydell     }
17803da26f11SPeter Maydell 
17813da26f11SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
17823da26f11SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
17833da26f11SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
17843da26f11SPeter Maydell         return false;
17853da26f11SPeter Maydell     }
17863da26f11SPeter Maydell 
17873da26f11SPeter Maydell     if ((a->vm | a->vd) & a->q) {
17883da26f11SPeter Maydell         return false;
17893da26f11SPeter Maydell     }
17903da26f11SPeter Maydell 
17913da26f11SPeter Maydell     if (!vfp_access_check(s)) {
17923da26f11SPeter Maydell         return true;
17933da26f11SPeter Maydell     }
17943da26f11SPeter Maydell 
1795a84d1d13SPeter Maydell     fpstatus = fpstatus_ptr(FPST_STD);
17963da26f11SPeter Maydell     shiftv = tcg_const_i32(a->shift);
17973da26f11SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
17983da26f11SPeter Maydell         tmp = neon_load_reg(a->vm, pass);
17993da26f11SPeter Maydell         fn(tmp, tmp, shiftv, fpstatus);
18003da26f11SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
18013da26f11SPeter Maydell     }
18023da26f11SPeter Maydell     tcg_temp_free_ptr(fpstatus);
18033da26f11SPeter Maydell     tcg_temp_free_i32(shiftv);
18043da26f11SPeter Maydell     return true;
18053da26f11SPeter Maydell }
18063da26f11SPeter Maydell 
18073da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC)                                           \
18083da26f11SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
18093da26f11SPeter Maydell     {                                                                   \
18103da26f11SPeter Maydell         return do_fp_2sh(s, a, FUNC);                                   \
18113da26f11SPeter Maydell     }
18123da26f11SPeter Maydell 
18133da26f11SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos)
18143da26f11SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos)
18153da26f11SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero)
18163da26f11SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero)
18172c35a39eSPeter Maydell 
18182c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
18192c35a39eSPeter Maydell {
18202c35a39eSPeter Maydell     /*
18212c35a39eSPeter Maydell      * Expand the encoded constant.
18222c35a39eSPeter Maydell      * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
18232c35a39eSPeter Maydell      * We choose to not special-case this and will behave as if a
18242c35a39eSPeter Maydell      * valid constant encoding of 0 had been given.
18252c35a39eSPeter Maydell      * cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
18262c35a39eSPeter Maydell      */
18272c35a39eSPeter Maydell     switch (cmode) {
18282c35a39eSPeter Maydell     case 0: case 1:
18292c35a39eSPeter Maydell         /* no-op */
18302c35a39eSPeter Maydell         break;
18312c35a39eSPeter Maydell     case 2: case 3:
18322c35a39eSPeter Maydell         imm <<= 8;
18332c35a39eSPeter Maydell         break;
18342c35a39eSPeter Maydell     case 4: case 5:
18352c35a39eSPeter Maydell         imm <<= 16;
18362c35a39eSPeter Maydell         break;
18372c35a39eSPeter Maydell     case 6: case 7:
18382c35a39eSPeter Maydell         imm <<= 24;
18392c35a39eSPeter Maydell         break;
18402c35a39eSPeter Maydell     case 8: case 9:
18412c35a39eSPeter Maydell         imm |= imm << 16;
18422c35a39eSPeter Maydell         break;
18432c35a39eSPeter Maydell     case 10: case 11:
18442c35a39eSPeter Maydell         imm = (imm << 8) | (imm << 24);
18452c35a39eSPeter Maydell         break;
18462c35a39eSPeter Maydell     case 12:
18472c35a39eSPeter Maydell         imm = (imm << 8) | 0xff;
18482c35a39eSPeter Maydell         break;
18492c35a39eSPeter Maydell     case 13:
18502c35a39eSPeter Maydell         imm = (imm << 16) | 0xffff;
18512c35a39eSPeter Maydell         break;
18522c35a39eSPeter Maydell     case 14:
18532c35a39eSPeter Maydell         if (op) {
18542c35a39eSPeter Maydell             /*
18552c35a39eSPeter Maydell              * This is the only case where the top and bottom 32 bits
18562c35a39eSPeter Maydell              * of the encoded constant differ.
18572c35a39eSPeter Maydell              */
18582c35a39eSPeter Maydell             uint64_t imm64 = 0;
18592c35a39eSPeter Maydell             int n;
18602c35a39eSPeter Maydell 
18612c35a39eSPeter Maydell             for (n = 0; n < 8; n++) {
18622c35a39eSPeter Maydell                 if (imm & (1 << n)) {
18632c35a39eSPeter Maydell                     imm64 |= (0xffULL << (n * 8));
18642c35a39eSPeter Maydell                 }
18652c35a39eSPeter Maydell             }
18662c35a39eSPeter Maydell             return imm64;
18672c35a39eSPeter Maydell         }
18682c35a39eSPeter Maydell         imm |= (imm << 8) | (imm << 16) | (imm << 24);
18692c35a39eSPeter Maydell         break;
18702c35a39eSPeter Maydell     case 15:
18712c35a39eSPeter Maydell         imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
18722c35a39eSPeter Maydell             | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
18732c35a39eSPeter Maydell         break;
18742c35a39eSPeter Maydell     }
18752c35a39eSPeter Maydell     if (op) {
18762c35a39eSPeter Maydell         imm = ~imm;
18772c35a39eSPeter Maydell     }
18782c35a39eSPeter Maydell     return dup_const(MO_32, imm);
18792c35a39eSPeter Maydell }
18802c35a39eSPeter Maydell 
18812c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
18822c35a39eSPeter Maydell                         GVecGen2iFn *fn)
18832c35a39eSPeter Maydell {
18842c35a39eSPeter Maydell     uint64_t imm;
18852c35a39eSPeter Maydell     int reg_ofs, vec_size;
18862c35a39eSPeter Maydell 
18872c35a39eSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
18882c35a39eSPeter Maydell         return false;
18892c35a39eSPeter Maydell     }
18902c35a39eSPeter Maydell 
18912c35a39eSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
18922c35a39eSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
18932c35a39eSPeter Maydell         return false;
18942c35a39eSPeter Maydell     }
18952c35a39eSPeter Maydell 
18962c35a39eSPeter Maydell     if (a->vd & a->q) {
18972c35a39eSPeter Maydell         return false;
18982c35a39eSPeter Maydell     }
18992c35a39eSPeter Maydell 
19002c35a39eSPeter Maydell     if (!vfp_access_check(s)) {
19012c35a39eSPeter Maydell         return true;
19022c35a39eSPeter Maydell     }
19032c35a39eSPeter Maydell 
19042c35a39eSPeter Maydell     reg_ofs = neon_reg_offset(a->vd, 0);
19052c35a39eSPeter Maydell     vec_size = a->q ? 16 : 8;
19062c35a39eSPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
19072c35a39eSPeter Maydell 
19082c35a39eSPeter Maydell     fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size);
19092c35a39eSPeter Maydell     return true;
19102c35a39eSPeter Maydell }
19112c35a39eSPeter Maydell 
19122c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs,
19132c35a39eSPeter Maydell                         int64_t c, uint32_t oprsz, uint32_t maxsz)
19142c35a39eSPeter Maydell {
19152c35a39eSPeter Maydell     tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
19162c35a39eSPeter Maydell }
19172c35a39eSPeter Maydell 
19182c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a)
19192c35a39eSPeter Maydell {
19202c35a39eSPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
19212c35a39eSPeter Maydell     GVecGen2iFn *fn;
19222c35a39eSPeter Maydell 
19232c35a39eSPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
19242c35a39eSPeter Maydell         /* for op=1, the imm will be inverted, so BIC becomes AND. */
19252c35a39eSPeter Maydell         fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
19262c35a39eSPeter Maydell     } else {
19272c35a39eSPeter Maydell         /* There is one unallocated cmode/op combination in this space */
19282c35a39eSPeter Maydell         if (a->cmode == 15 && a->op == 1) {
19292c35a39eSPeter Maydell             return false;
19302c35a39eSPeter Maydell         }
19312c35a39eSPeter Maydell         fn = gen_VMOV_1r;
19322c35a39eSPeter Maydell     }
19332c35a39eSPeter Maydell     return do_1reg_imm(s, a, fn);
19342c35a39eSPeter Maydell }
1935b28be095SPeter Maydell 
1936b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
1937b28be095SPeter Maydell                            NeonGenWidenFn *widenfn,
1938b28be095SPeter Maydell                            NeonGenTwo64OpFn *opfn,
1939b28be095SPeter Maydell                            bool src1_wide)
1940b28be095SPeter Maydell {
1941b28be095SPeter Maydell     /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */
1942b28be095SPeter Maydell     TCGv_i64 rn0_64, rn1_64, rm_64;
1943b28be095SPeter Maydell     TCGv_i32 rm;
1944b28be095SPeter Maydell 
1945b28be095SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1946b28be095SPeter Maydell         return false;
1947b28be095SPeter Maydell     }
1948b28be095SPeter Maydell 
1949b28be095SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1950b28be095SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1951b28be095SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1952b28be095SPeter Maydell         return false;
1953b28be095SPeter Maydell     }
1954b28be095SPeter Maydell 
1955b28be095SPeter Maydell     if (!widenfn || !opfn) {
1956b28be095SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
1957b28be095SPeter Maydell         return false;
1958b28be095SPeter Maydell     }
1959b28be095SPeter Maydell 
1960b28be095SPeter Maydell     if ((a->vd & 1) || (src1_wide && (a->vn & 1))) {
1961b28be095SPeter Maydell         return false;
1962b28be095SPeter Maydell     }
1963b28be095SPeter Maydell 
1964b28be095SPeter Maydell     if (!vfp_access_check(s)) {
1965b28be095SPeter Maydell         return true;
1966b28be095SPeter Maydell     }
1967b28be095SPeter Maydell 
1968b28be095SPeter Maydell     rn0_64 = tcg_temp_new_i64();
1969b28be095SPeter Maydell     rn1_64 = tcg_temp_new_i64();
1970b28be095SPeter Maydell     rm_64 = tcg_temp_new_i64();
1971b28be095SPeter Maydell 
1972b28be095SPeter Maydell     if (src1_wide) {
1973b28be095SPeter Maydell         neon_load_reg64(rn0_64, a->vn);
1974b28be095SPeter Maydell     } else {
1975b28be095SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, 0);
1976b28be095SPeter Maydell         widenfn(rn0_64, tmp);
1977b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1978b28be095SPeter Maydell     }
1979b28be095SPeter Maydell     rm = neon_load_reg(a->vm, 0);
1980b28be095SPeter Maydell 
1981b28be095SPeter Maydell     widenfn(rm_64, rm);
1982b28be095SPeter Maydell     tcg_temp_free_i32(rm);
1983b28be095SPeter Maydell     opfn(rn0_64, rn0_64, rm_64);
1984b28be095SPeter Maydell 
1985b28be095SPeter Maydell     /*
1986b28be095SPeter Maydell      * Load second pass inputs before storing the first pass result, to
1987b28be095SPeter Maydell      * avoid incorrect results if a narrow input overlaps with the result.
1988b28be095SPeter Maydell      */
1989b28be095SPeter Maydell     if (src1_wide) {
1990b28be095SPeter Maydell         neon_load_reg64(rn1_64, a->vn + 1);
1991b28be095SPeter Maydell     } else {
1992b28be095SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, 1);
1993b28be095SPeter Maydell         widenfn(rn1_64, tmp);
1994b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1995b28be095SPeter Maydell     }
1996b28be095SPeter Maydell     rm = neon_load_reg(a->vm, 1);
1997b28be095SPeter Maydell 
1998b28be095SPeter Maydell     neon_store_reg64(rn0_64, a->vd);
1999b28be095SPeter Maydell 
2000b28be095SPeter Maydell     widenfn(rm_64, rm);
2001b28be095SPeter Maydell     tcg_temp_free_i32(rm);
2002b28be095SPeter Maydell     opfn(rn1_64, rn1_64, rm_64);
2003b28be095SPeter Maydell     neon_store_reg64(rn1_64, a->vd + 1);
2004b28be095SPeter Maydell 
2005b28be095SPeter Maydell     tcg_temp_free_i64(rn0_64);
2006b28be095SPeter Maydell     tcg_temp_free_i64(rn1_64);
2007b28be095SPeter Maydell     tcg_temp_free_i64(rm_64);
2008b28be095SPeter Maydell 
2009b28be095SPeter Maydell     return true;
2010b28be095SPeter Maydell }
2011b28be095SPeter Maydell 
2012b28be095SPeter Maydell #define DO_PREWIDEN(INSN, S, EXT, OP, SRC1WIDE)                         \
2013b28be095SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
2014b28be095SPeter Maydell     {                                                                   \
2015b28be095SPeter Maydell         static NeonGenWidenFn * const widenfn[] = {                     \
2016b28be095SPeter Maydell             gen_helper_neon_widen_##S##8,                               \
2017b28be095SPeter Maydell             gen_helper_neon_widen_##S##16,                              \
2018b28be095SPeter Maydell             tcg_gen_##EXT##_i32_i64,                                    \
2019b28be095SPeter Maydell             NULL,                                                       \
2020b28be095SPeter Maydell         };                                                              \
2021b28be095SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
2022b28be095SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
2023b28be095SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
2024b28be095SPeter Maydell             tcg_gen_##OP##_i64,                                         \
2025b28be095SPeter Maydell             NULL,                                                       \
2026b28be095SPeter Maydell         };                                                              \
2027b28be095SPeter Maydell         return do_prewiden_3d(s, a, widenfn[a->size],                   \
2028b28be095SPeter Maydell                               addfn[a->size], SRC1WIDE);                \
2029b28be095SPeter Maydell     }
2030b28be095SPeter Maydell 
2031b28be095SPeter Maydell DO_PREWIDEN(VADDL_S, s, ext, add, false)
2032b28be095SPeter Maydell DO_PREWIDEN(VADDL_U, u, extu, add, false)
2033b28be095SPeter Maydell DO_PREWIDEN(VSUBL_S, s, ext, sub, false)
2034b28be095SPeter Maydell DO_PREWIDEN(VSUBL_U, u, extu, sub, false)
2035b28be095SPeter Maydell DO_PREWIDEN(VADDW_S, s, ext, add, true)
2036b28be095SPeter Maydell DO_PREWIDEN(VADDW_U, u, extu, add, true)
2037b28be095SPeter Maydell DO_PREWIDEN(VSUBW_S, s, ext, sub, true)
2038b28be095SPeter Maydell DO_PREWIDEN(VSUBW_U, u, extu, sub, true)
20390fa1ab03SPeter Maydell 
20400fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
20410fa1ab03SPeter Maydell                          NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn)
20420fa1ab03SPeter Maydell {
20430fa1ab03SPeter Maydell     /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */
20440fa1ab03SPeter Maydell     TCGv_i64 rn_64, rm_64;
20450fa1ab03SPeter Maydell     TCGv_i32 rd0, rd1;
20460fa1ab03SPeter Maydell 
20470fa1ab03SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
20480fa1ab03SPeter Maydell         return false;
20490fa1ab03SPeter Maydell     }
20500fa1ab03SPeter Maydell 
20510fa1ab03SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
20520fa1ab03SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
20530fa1ab03SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
20540fa1ab03SPeter Maydell         return false;
20550fa1ab03SPeter Maydell     }
20560fa1ab03SPeter Maydell 
20570fa1ab03SPeter Maydell     if (!opfn || !narrowfn) {
20580fa1ab03SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
20590fa1ab03SPeter Maydell         return false;
20600fa1ab03SPeter Maydell     }
20610fa1ab03SPeter Maydell 
20620fa1ab03SPeter Maydell     if ((a->vn | a->vm) & 1) {
20630fa1ab03SPeter Maydell         return false;
20640fa1ab03SPeter Maydell     }
20650fa1ab03SPeter Maydell 
20660fa1ab03SPeter Maydell     if (!vfp_access_check(s)) {
20670fa1ab03SPeter Maydell         return true;
20680fa1ab03SPeter Maydell     }
20690fa1ab03SPeter Maydell 
20700fa1ab03SPeter Maydell     rn_64 = tcg_temp_new_i64();
20710fa1ab03SPeter Maydell     rm_64 = tcg_temp_new_i64();
20720fa1ab03SPeter Maydell     rd0 = tcg_temp_new_i32();
20730fa1ab03SPeter Maydell     rd1 = tcg_temp_new_i32();
20740fa1ab03SPeter Maydell 
20750fa1ab03SPeter Maydell     neon_load_reg64(rn_64, a->vn);
20760fa1ab03SPeter Maydell     neon_load_reg64(rm_64, a->vm);
20770fa1ab03SPeter Maydell 
20780fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
20790fa1ab03SPeter Maydell 
20800fa1ab03SPeter Maydell     narrowfn(rd0, rn_64);
20810fa1ab03SPeter Maydell 
20820fa1ab03SPeter Maydell     neon_load_reg64(rn_64, a->vn + 1);
20830fa1ab03SPeter Maydell     neon_load_reg64(rm_64, a->vm + 1);
20840fa1ab03SPeter Maydell 
20850fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
20860fa1ab03SPeter Maydell 
20870fa1ab03SPeter Maydell     narrowfn(rd1, rn_64);
20880fa1ab03SPeter Maydell 
20890fa1ab03SPeter Maydell     neon_store_reg(a->vd, 0, rd0);
20900fa1ab03SPeter Maydell     neon_store_reg(a->vd, 1, rd1);
20910fa1ab03SPeter Maydell 
20920fa1ab03SPeter Maydell     tcg_temp_free_i64(rn_64);
20930fa1ab03SPeter Maydell     tcg_temp_free_i64(rm_64);
20940fa1ab03SPeter Maydell 
20950fa1ab03SPeter Maydell     return true;
20960fa1ab03SPeter Maydell }
20970fa1ab03SPeter Maydell 
20980fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP)                       \
20990fa1ab03SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
21000fa1ab03SPeter Maydell     {                                                                   \
21010fa1ab03SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
21020fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
21030fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
21040fa1ab03SPeter Maydell             tcg_gen_##OP##_i64,                                         \
21050fa1ab03SPeter Maydell             NULL,                                                       \
21060fa1ab03SPeter Maydell         };                                                              \
21070fa1ab03SPeter Maydell         static NeonGenNarrowFn * const narrowfn[] = {                   \
21080fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u8,                     \
21090fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u16,                    \
21100fa1ab03SPeter Maydell             EXTOP,                                                      \
21110fa1ab03SPeter Maydell             NULL,                                                       \
21120fa1ab03SPeter Maydell         };                                                              \
21130fa1ab03SPeter Maydell         return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]);   \
21140fa1ab03SPeter Maydell     }
21150fa1ab03SPeter Maydell 
21160fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn)
21170fa1ab03SPeter Maydell {
21180fa1ab03SPeter Maydell     tcg_gen_addi_i64(rn, rn, 1u << 31);
21190fa1ab03SPeter Maydell     tcg_gen_extrh_i64_i32(rd, rn);
21200fa1ab03SPeter Maydell }
21210fa1ab03SPeter Maydell 
21220fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32)
21230fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32)
21240fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32)
21250fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32)
2126f5b28401SPeter Maydell 
2127f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a,
2128f5b28401SPeter Maydell                        NeonGenTwoOpWidenFn *opfn,
2129f5b28401SPeter Maydell                        NeonGenTwo64OpFn *accfn)
2130f5b28401SPeter Maydell {
2131f5b28401SPeter Maydell     /*
2132f5b28401SPeter Maydell      * 3-regs different lengths, long operations.
2133f5b28401SPeter Maydell      * These perform an operation on two inputs that returns a double-width
2134f5b28401SPeter Maydell      * result, and then possibly perform an accumulation operation of
2135f5b28401SPeter Maydell      * that result into the double-width destination.
2136f5b28401SPeter Maydell      */
2137f5b28401SPeter Maydell     TCGv_i64 rd0, rd1, tmp;
2138f5b28401SPeter Maydell     TCGv_i32 rn, rm;
2139f5b28401SPeter Maydell 
2140f5b28401SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2141f5b28401SPeter Maydell         return false;
2142f5b28401SPeter Maydell     }
2143f5b28401SPeter Maydell 
2144f5b28401SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2145f5b28401SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2146f5b28401SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2147f5b28401SPeter Maydell         return false;
2148f5b28401SPeter Maydell     }
2149f5b28401SPeter Maydell 
2150f5b28401SPeter Maydell     if (!opfn) {
2151f5b28401SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
2152f5b28401SPeter Maydell         return false;
2153f5b28401SPeter Maydell     }
2154f5b28401SPeter Maydell 
2155f5b28401SPeter Maydell     if (a->vd & 1) {
2156f5b28401SPeter Maydell         return false;
2157f5b28401SPeter Maydell     }
2158f5b28401SPeter Maydell 
2159f5b28401SPeter Maydell     if (!vfp_access_check(s)) {
2160f5b28401SPeter Maydell         return true;
2161f5b28401SPeter Maydell     }
2162f5b28401SPeter Maydell 
2163f5b28401SPeter Maydell     rd0 = tcg_temp_new_i64();
2164f5b28401SPeter Maydell     rd1 = tcg_temp_new_i64();
2165f5b28401SPeter Maydell 
2166f5b28401SPeter Maydell     rn = neon_load_reg(a->vn, 0);
2167f5b28401SPeter Maydell     rm = neon_load_reg(a->vm, 0);
2168f5b28401SPeter Maydell     opfn(rd0, rn, rm);
2169f5b28401SPeter Maydell     tcg_temp_free_i32(rn);
2170f5b28401SPeter Maydell     tcg_temp_free_i32(rm);
2171f5b28401SPeter Maydell 
2172f5b28401SPeter Maydell     rn = neon_load_reg(a->vn, 1);
2173f5b28401SPeter Maydell     rm = neon_load_reg(a->vm, 1);
2174f5b28401SPeter Maydell     opfn(rd1, rn, rm);
2175f5b28401SPeter Maydell     tcg_temp_free_i32(rn);
2176f5b28401SPeter Maydell     tcg_temp_free_i32(rm);
2177f5b28401SPeter Maydell 
2178f5b28401SPeter Maydell     /* Don't store results until after all loads: they might overlap */
2179f5b28401SPeter Maydell     if (accfn) {
2180f5b28401SPeter Maydell         tmp = tcg_temp_new_i64();
2181f5b28401SPeter Maydell         neon_load_reg64(tmp, a->vd);
2182f5b28401SPeter Maydell         accfn(tmp, tmp, rd0);
2183f5b28401SPeter Maydell         neon_store_reg64(tmp, a->vd);
2184f5b28401SPeter Maydell         neon_load_reg64(tmp, a->vd + 1);
2185f5b28401SPeter Maydell         accfn(tmp, tmp, rd1);
2186f5b28401SPeter Maydell         neon_store_reg64(tmp, a->vd + 1);
2187f5b28401SPeter Maydell         tcg_temp_free_i64(tmp);
2188f5b28401SPeter Maydell     } else {
2189f5b28401SPeter Maydell         neon_store_reg64(rd0, a->vd);
2190f5b28401SPeter Maydell         neon_store_reg64(rd1, a->vd + 1);
2191f5b28401SPeter Maydell     }
2192f5b28401SPeter Maydell 
2193f5b28401SPeter Maydell     tcg_temp_free_i64(rd0);
2194f5b28401SPeter Maydell     tcg_temp_free_i64(rd1);
2195f5b28401SPeter Maydell 
2196f5b28401SPeter Maydell     return true;
2197f5b28401SPeter Maydell }
2198f5b28401SPeter Maydell 
2199f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a)
2200f5b28401SPeter Maydell {
2201f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2202f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2203f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2204f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2205f5b28401SPeter Maydell         NULL,
2206f5b28401SPeter Maydell     };
2207f5b28401SPeter Maydell 
2208f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2209f5b28401SPeter Maydell }
2210f5b28401SPeter Maydell 
2211f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a)
2212f5b28401SPeter Maydell {
2213f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2214f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2215f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2216f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2217f5b28401SPeter Maydell         NULL,
2218f5b28401SPeter Maydell     };
2219f5b28401SPeter Maydell 
2220f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2221f5b28401SPeter Maydell }
2222f5b28401SPeter Maydell 
2223f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a)
2224f5b28401SPeter Maydell {
2225f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2226f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2227f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2228f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2229f5b28401SPeter Maydell         NULL,
2230f5b28401SPeter Maydell     };
2231f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2232f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2233f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2234f5b28401SPeter Maydell         tcg_gen_add_i64,
2235f5b28401SPeter Maydell         NULL,
2236f5b28401SPeter Maydell     };
2237f5b28401SPeter Maydell 
2238f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2239f5b28401SPeter Maydell }
2240f5b28401SPeter Maydell 
2241f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
2242f5b28401SPeter Maydell {
2243f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2244f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2245f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2246f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2247f5b28401SPeter Maydell         NULL,
2248f5b28401SPeter Maydell     };
2249f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2250f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2251f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2252f5b28401SPeter Maydell         tcg_gen_add_i64,
2253f5b28401SPeter Maydell         NULL,
2254f5b28401SPeter Maydell     };
2255f5b28401SPeter Maydell 
2256f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2257f5b28401SPeter Maydell }
22583a1d9eb0SPeter Maydell 
22593a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
22603a1d9eb0SPeter Maydell {
22613a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
22623a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
22633a1d9eb0SPeter Maydell 
22643a1d9eb0SPeter Maydell     tcg_gen_muls2_i32(lo, hi, rn, rm);
22653a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
22663a1d9eb0SPeter Maydell 
22673a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
22683a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
22693a1d9eb0SPeter Maydell }
22703a1d9eb0SPeter Maydell 
22713a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
22723a1d9eb0SPeter Maydell {
22733a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
22743a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
22753a1d9eb0SPeter Maydell 
22763a1d9eb0SPeter Maydell     tcg_gen_mulu2_i32(lo, hi, rn, rm);
22773a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
22783a1d9eb0SPeter Maydell 
22793a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
22803a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
22813a1d9eb0SPeter Maydell }
22823a1d9eb0SPeter Maydell 
22833a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a)
22843a1d9eb0SPeter Maydell {
22853a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22863a1d9eb0SPeter Maydell         gen_helper_neon_mull_s8,
22873a1d9eb0SPeter Maydell         gen_helper_neon_mull_s16,
22883a1d9eb0SPeter Maydell         gen_mull_s32,
22893a1d9eb0SPeter Maydell         NULL,
22903a1d9eb0SPeter Maydell     };
22913a1d9eb0SPeter Maydell 
22923a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
22933a1d9eb0SPeter Maydell }
22943a1d9eb0SPeter Maydell 
22953a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
22963a1d9eb0SPeter Maydell {
22973a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22983a1d9eb0SPeter Maydell         gen_helper_neon_mull_u8,
22993a1d9eb0SPeter Maydell         gen_helper_neon_mull_u16,
23003a1d9eb0SPeter Maydell         gen_mull_u32,
23013a1d9eb0SPeter Maydell         NULL,
23023a1d9eb0SPeter Maydell     };
23033a1d9eb0SPeter Maydell 
23043a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
23053a1d9eb0SPeter Maydell }
23063a1d9eb0SPeter Maydell 
23073a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC)                                         \
23083a1d9eb0SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
23093a1d9eb0SPeter Maydell     {                                                                   \
23103a1d9eb0SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
23113a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##8,                                  \
23123a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
23133a1d9eb0SPeter Maydell             gen_##MULL##32,                                             \
23143a1d9eb0SPeter Maydell             NULL,                                                       \
23153a1d9eb0SPeter Maydell         };                                                              \
23163a1d9eb0SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
23173a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u16,                               \
23183a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
23193a1d9eb0SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
23203a1d9eb0SPeter Maydell             NULL,                                                       \
23213a1d9eb0SPeter Maydell         };                                                              \
23223a1d9eb0SPeter Maydell         return do_long_3d(s, a, opfn[a->size], accfn[a->size]);         \
23233a1d9eb0SPeter Maydell     }
23243a1d9eb0SPeter Maydell 
23253a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add)
23263a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add)
23273a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub)
23283a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub)
23299546ca59SPeter Maydell 
23309546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
23319546ca59SPeter Maydell {
23329546ca59SPeter Maydell     gen_helper_neon_mull_s16(rd, rn, rm);
23339546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd);
23349546ca59SPeter Maydell }
23359546ca59SPeter Maydell 
23369546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
23379546ca59SPeter Maydell {
23389546ca59SPeter Maydell     gen_mull_s32(rd, rn, rm);
23399546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd);
23409546ca59SPeter Maydell }
23419546ca59SPeter Maydell 
23429546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a)
23439546ca59SPeter Maydell {
23449546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
23459546ca59SPeter Maydell         NULL,
23469546ca59SPeter Maydell         gen_VQDMULL_16,
23479546ca59SPeter Maydell         gen_VQDMULL_32,
23489546ca59SPeter Maydell         NULL,
23499546ca59SPeter Maydell     };
23509546ca59SPeter Maydell 
23519546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
23529546ca59SPeter Maydell }
23539546ca59SPeter Maydell 
23549546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
23559546ca59SPeter Maydell {
23569546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
23579546ca59SPeter Maydell }
23589546ca59SPeter Maydell 
23599546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
23609546ca59SPeter Maydell {
23619546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
23629546ca59SPeter Maydell }
23639546ca59SPeter Maydell 
23649546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a)
23659546ca59SPeter Maydell {
23669546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
23679546ca59SPeter Maydell         NULL,
23689546ca59SPeter Maydell         gen_VQDMULL_16,
23699546ca59SPeter Maydell         gen_VQDMULL_32,
23709546ca59SPeter Maydell         NULL,
23719546ca59SPeter Maydell     };
23729546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
23739546ca59SPeter Maydell         NULL,
23749546ca59SPeter Maydell         gen_VQDMLAL_acc_16,
23759546ca59SPeter Maydell         gen_VQDMLAL_acc_32,
23769546ca59SPeter Maydell         NULL,
23779546ca59SPeter Maydell     };
23789546ca59SPeter Maydell 
23799546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
23809546ca59SPeter Maydell }
23819546ca59SPeter Maydell 
23829546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
23839546ca59SPeter Maydell {
23849546ca59SPeter Maydell     gen_helper_neon_negl_u32(rm, rm);
23859546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
23869546ca59SPeter Maydell }
23879546ca59SPeter Maydell 
23889546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
23899546ca59SPeter Maydell {
23909546ca59SPeter Maydell     tcg_gen_neg_i64(rm, rm);
23919546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
23929546ca59SPeter Maydell }
23939546ca59SPeter Maydell 
23949546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a)
23959546ca59SPeter Maydell {
23969546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
23979546ca59SPeter Maydell         NULL,
23989546ca59SPeter Maydell         gen_VQDMULL_16,
23999546ca59SPeter Maydell         gen_VQDMULL_32,
24009546ca59SPeter Maydell         NULL,
24019546ca59SPeter Maydell     };
24029546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
24039546ca59SPeter Maydell         NULL,
24049546ca59SPeter Maydell         gen_VQDMLSL_acc_16,
24059546ca59SPeter Maydell         gen_VQDMLSL_acc_32,
24069546ca59SPeter Maydell         NULL,
24079546ca59SPeter Maydell     };
24089546ca59SPeter Maydell 
24099546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
24109546ca59SPeter Maydell }
241118fb58d5SPeter Maydell 
241218fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
241318fb58d5SPeter Maydell {
241418fb58d5SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
241518fb58d5SPeter Maydell 
241618fb58d5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
241718fb58d5SPeter Maydell         return false;
241818fb58d5SPeter Maydell     }
241918fb58d5SPeter Maydell 
242018fb58d5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
242118fb58d5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
242218fb58d5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
242318fb58d5SPeter Maydell         return false;
242418fb58d5SPeter Maydell     }
242518fb58d5SPeter Maydell 
242618fb58d5SPeter Maydell     if (a->vd & 1) {
242718fb58d5SPeter Maydell         return false;
242818fb58d5SPeter Maydell     }
242918fb58d5SPeter Maydell 
243018fb58d5SPeter Maydell     switch (a->size) {
243118fb58d5SPeter Maydell     case 0:
243218fb58d5SPeter Maydell         fn_gvec = gen_helper_neon_pmull_h;
243318fb58d5SPeter Maydell         break;
243418fb58d5SPeter Maydell     case 2:
243518fb58d5SPeter Maydell         if (!dc_isar_feature(aa32_pmull, s)) {
243618fb58d5SPeter Maydell             return false;
243718fb58d5SPeter Maydell         }
243818fb58d5SPeter Maydell         fn_gvec = gen_helper_gvec_pmull_q;
243918fb58d5SPeter Maydell         break;
244018fb58d5SPeter Maydell     default:
244118fb58d5SPeter Maydell         return false;
244218fb58d5SPeter Maydell     }
244318fb58d5SPeter Maydell 
244418fb58d5SPeter Maydell     if (!vfp_access_check(s)) {
244518fb58d5SPeter Maydell         return true;
244618fb58d5SPeter Maydell     }
244718fb58d5SPeter Maydell 
244818fb58d5SPeter Maydell     tcg_gen_gvec_3_ool(neon_reg_offset(a->vd, 0),
244918fb58d5SPeter Maydell                        neon_reg_offset(a->vn, 0),
245018fb58d5SPeter Maydell                        neon_reg_offset(a->vm, 0),
245118fb58d5SPeter Maydell                        16, 16, 0, fn_gvec);
245218fb58d5SPeter Maydell     return true;
245318fb58d5SPeter Maydell }
245496fc80f5SPeter Maydell 
245596fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var)
245696fc80f5SPeter Maydell {
245796fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
245896fc80f5SPeter Maydell     tcg_gen_ext16u_i32(var, var);
245996fc80f5SPeter Maydell     tcg_gen_shli_i32(tmp, var, 16);
246096fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
246196fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
246296fc80f5SPeter Maydell }
246396fc80f5SPeter Maydell 
246496fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var)
246596fc80f5SPeter Maydell {
246696fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
246796fc80f5SPeter Maydell     tcg_gen_andi_i32(var, var, 0xffff0000);
246896fc80f5SPeter Maydell     tcg_gen_shri_i32(tmp, var, 16);
246996fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
247096fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
247196fc80f5SPeter Maydell }
247296fc80f5SPeter Maydell 
247396fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg)
247496fc80f5SPeter Maydell {
247596fc80f5SPeter Maydell     TCGv_i32 tmp;
247696fc80f5SPeter Maydell     if (size == 1) {
247796fc80f5SPeter Maydell         tmp = neon_load_reg(reg & 7, reg >> 4);
247896fc80f5SPeter Maydell         if (reg & 8) {
247996fc80f5SPeter Maydell             gen_neon_dup_high16(tmp);
248096fc80f5SPeter Maydell         } else {
248196fc80f5SPeter Maydell             gen_neon_dup_low16(tmp);
248296fc80f5SPeter Maydell         }
248396fc80f5SPeter Maydell     } else {
248496fc80f5SPeter Maydell         tmp = neon_load_reg(reg & 15, reg >> 4);
248596fc80f5SPeter Maydell     }
248696fc80f5SPeter Maydell     return tmp;
248796fc80f5SPeter Maydell }
248896fc80f5SPeter Maydell 
248996fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a,
249096fc80f5SPeter Maydell                        NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn)
249196fc80f5SPeter Maydell {
249296fc80f5SPeter Maydell     /*
249396fc80f5SPeter Maydell      * Two registers and a scalar: perform an operation between
249496fc80f5SPeter Maydell      * the input elements and the scalar, and then possibly
249596fc80f5SPeter Maydell      * perform an accumulation operation of that result into the
249696fc80f5SPeter Maydell      * destination.
249796fc80f5SPeter Maydell      */
249896fc80f5SPeter Maydell     TCGv_i32 scalar;
249996fc80f5SPeter Maydell     int pass;
250096fc80f5SPeter Maydell 
250196fc80f5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
250296fc80f5SPeter Maydell         return false;
250396fc80f5SPeter Maydell     }
250496fc80f5SPeter Maydell 
250596fc80f5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
250696fc80f5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
250796fc80f5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
250896fc80f5SPeter Maydell         return false;
250996fc80f5SPeter Maydell     }
251096fc80f5SPeter Maydell 
251196fc80f5SPeter Maydell     if (!opfn) {
251296fc80f5SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
251396fc80f5SPeter Maydell         return false;
251496fc80f5SPeter Maydell     }
251596fc80f5SPeter Maydell 
251696fc80f5SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
251796fc80f5SPeter Maydell         return false;
251896fc80f5SPeter Maydell     }
251996fc80f5SPeter Maydell 
252096fc80f5SPeter Maydell     if (!vfp_access_check(s)) {
252196fc80f5SPeter Maydell         return true;
252296fc80f5SPeter Maydell     }
252396fc80f5SPeter Maydell 
252496fc80f5SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
252596fc80f5SPeter Maydell 
252696fc80f5SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
252796fc80f5SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vn, pass);
252896fc80f5SPeter Maydell         opfn(tmp, tmp, scalar);
252996fc80f5SPeter Maydell         if (accfn) {
253096fc80f5SPeter Maydell             TCGv_i32 rd = neon_load_reg(a->vd, pass);
253196fc80f5SPeter Maydell             accfn(tmp, rd, tmp);
253296fc80f5SPeter Maydell             tcg_temp_free_i32(rd);
253396fc80f5SPeter Maydell         }
253496fc80f5SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
253596fc80f5SPeter Maydell     }
253696fc80f5SPeter Maydell     tcg_temp_free_i32(scalar);
253796fc80f5SPeter Maydell     return true;
253896fc80f5SPeter Maydell }
253996fc80f5SPeter Maydell 
254096fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a)
254196fc80f5SPeter Maydell {
254296fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
254396fc80f5SPeter Maydell         NULL,
254496fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
254596fc80f5SPeter Maydell         tcg_gen_mul_i32,
254696fc80f5SPeter Maydell         NULL,
254796fc80f5SPeter Maydell     };
254896fc80f5SPeter Maydell 
254996fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
255096fc80f5SPeter Maydell }
255196fc80f5SPeter Maydell 
255296fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a)
255396fc80f5SPeter Maydell {
255496fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
255596fc80f5SPeter Maydell         NULL,
255696fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
255796fc80f5SPeter Maydell         tcg_gen_mul_i32,
255896fc80f5SPeter Maydell         NULL,
255996fc80f5SPeter Maydell     };
256096fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
256196fc80f5SPeter Maydell         NULL,
256296fc80f5SPeter Maydell         gen_helper_neon_add_u16,
256396fc80f5SPeter Maydell         tcg_gen_add_i32,
256496fc80f5SPeter Maydell         NULL,
256596fc80f5SPeter Maydell     };
256696fc80f5SPeter Maydell 
256796fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
256896fc80f5SPeter Maydell }
256996fc80f5SPeter Maydell 
257096fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a)
257196fc80f5SPeter Maydell {
257296fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
257396fc80f5SPeter Maydell         NULL,
257496fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
257596fc80f5SPeter Maydell         tcg_gen_mul_i32,
257696fc80f5SPeter Maydell         NULL,
257796fc80f5SPeter Maydell     };
257896fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
257996fc80f5SPeter Maydell         NULL,
258096fc80f5SPeter Maydell         gen_helper_neon_sub_u16,
258196fc80f5SPeter Maydell         tcg_gen_sub_i32,
258296fc80f5SPeter Maydell         NULL,
258396fc80f5SPeter Maydell     };
258496fc80f5SPeter Maydell 
258596fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
258696fc80f5SPeter Maydell }
258785ac9aefSPeter Maydell 
258885ac9aefSPeter Maydell /*
258985ac9aefSPeter Maydell  * Rather than have a float-specific version of do_2scalar just for
259085ac9aefSPeter Maydell  * three insns, we wrap a NeonGenTwoSingleOpFn to turn it into
259185ac9aefSPeter Maydell  * a NeonGenTwoOpFn.
259285ac9aefSPeter Maydell  */
259385ac9aefSPeter Maydell #define WRAP_FP_FN(WRAPNAME, FUNC)                              \
259485ac9aefSPeter Maydell     static void WRAPNAME(TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \
259585ac9aefSPeter Maydell     {                                                           \
2596a84d1d13SPeter Maydell         TCGv_ptr fpstatus = fpstatus_ptr(FPST_STD);             \
259785ac9aefSPeter Maydell         FUNC(rd, rn, rm, fpstatus);                             \
259885ac9aefSPeter Maydell         tcg_temp_free_ptr(fpstatus);                            \
259985ac9aefSPeter Maydell     }
260085ac9aefSPeter Maydell 
260185ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls)
260285ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds)
260385ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs)
260485ac9aefSPeter Maydell 
260585ac9aefSPeter Maydell static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a)
260685ac9aefSPeter Maydell {
260785ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
260885ac9aefSPeter Maydell         NULL,
260985ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
261085ac9aefSPeter Maydell         gen_VMUL_F_mul,
261185ac9aefSPeter Maydell         NULL,
261285ac9aefSPeter Maydell     };
261385ac9aefSPeter Maydell 
261485ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
261585ac9aefSPeter Maydell }
261685ac9aefSPeter Maydell 
261785ac9aefSPeter Maydell static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a)
261885ac9aefSPeter Maydell {
261985ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
262085ac9aefSPeter Maydell         NULL,
262185ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
262285ac9aefSPeter Maydell         gen_VMUL_F_mul,
262385ac9aefSPeter Maydell         NULL,
262485ac9aefSPeter Maydell     };
262585ac9aefSPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
262685ac9aefSPeter Maydell         NULL,
262785ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
262885ac9aefSPeter Maydell         gen_VMUL_F_add,
262985ac9aefSPeter Maydell         NULL,
263085ac9aefSPeter Maydell     };
263185ac9aefSPeter Maydell 
263285ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
263385ac9aefSPeter Maydell }
263485ac9aefSPeter Maydell 
263585ac9aefSPeter Maydell static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a)
263685ac9aefSPeter Maydell {
263785ac9aefSPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
263885ac9aefSPeter Maydell         NULL,
263985ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
264085ac9aefSPeter Maydell         gen_VMUL_F_mul,
264185ac9aefSPeter Maydell         NULL,
264285ac9aefSPeter Maydell     };
264385ac9aefSPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
264485ac9aefSPeter Maydell         NULL,
264585ac9aefSPeter Maydell         NULL, /* TODO: fp16 support */
264685ac9aefSPeter Maydell         gen_VMUL_F_sub,
264785ac9aefSPeter Maydell         NULL,
264885ac9aefSPeter Maydell     };
264985ac9aefSPeter Maydell 
265085ac9aefSPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
265185ac9aefSPeter Maydell }
2652b2fc7be9SPeter Maydell 
2653b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
2654b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
2655b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16)
2656b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32)
2657b2fc7be9SPeter Maydell 
2658b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a)
2659b2fc7be9SPeter Maydell {
2660b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2661b2fc7be9SPeter Maydell         NULL,
2662b2fc7be9SPeter Maydell         gen_VQDMULH_16,
2663b2fc7be9SPeter Maydell         gen_VQDMULH_32,
2664b2fc7be9SPeter Maydell         NULL,
2665b2fc7be9SPeter Maydell     };
2666b2fc7be9SPeter Maydell 
2667b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2668b2fc7be9SPeter Maydell }
2669b2fc7be9SPeter Maydell 
2670b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a)
2671b2fc7be9SPeter Maydell {
2672b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2673b2fc7be9SPeter Maydell         NULL,
2674b2fc7be9SPeter Maydell         gen_VQRDMULH_16,
2675b2fc7be9SPeter Maydell         gen_VQRDMULH_32,
2676b2fc7be9SPeter Maydell         NULL,
2677b2fc7be9SPeter Maydell     };
2678b2fc7be9SPeter Maydell 
2679b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2680b2fc7be9SPeter Maydell }
2681aa318f5bSPeter Maydell 
2682aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a,
2683aa318f5bSPeter Maydell                             NeonGenThreeOpEnvFn *opfn)
2684aa318f5bSPeter Maydell {
2685aa318f5bSPeter Maydell     /*
2686aa318f5bSPeter Maydell      * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn
2687aa318f5bSPeter Maydell      * performs a kind of fused op-then-accumulate using a helper
2688aa318f5bSPeter Maydell      * function that takes all of rd, rn and the scalar at once.
2689aa318f5bSPeter Maydell      */
2690aa318f5bSPeter Maydell     TCGv_i32 scalar;
2691aa318f5bSPeter Maydell     int pass;
2692aa318f5bSPeter Maydell 
2693aa318f5bSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2694aa318f5bSPeter Maydell         return false;
2695aa318f5bSPeter Maydell     }
2696aa318f5bSPeter Maydell 
2697aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_rdm, s)) {
2698aa318f5bSPeter Maydell         return false;
2699aa318f5bSPeter Maydell     }
2700aa318f5bSPeter Maydell 
2701aa318f5bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2702aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2703aa318f5bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2704aa318f5bSPeter Maydell         return false;
2705aa318f5bSPeter Maydell     }
2706aa318f5bSPeter Maydell 
2707aa318f5bSPeter Maydell     if (!opfn) {
2708aa318f5bSPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2709aa318f5bSPeter Maydell         return false;
2710aa318f5bSPeter Maydell     }
2711aa318f5bSPeter Maydell 
2712aa318f5bSPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2713aa318f5bSPeter Maydell         return false;
2714aa318f5bSPeter Maydell     }
2715aa318f5bSPeter Maydell 
2716aa318f5bSPeter Maydell     if (!vfp_access_check(s)) {
2717aa318f5bSPeter Maydell         return true;
2718aa318f5bSPeter Maydell     }
2719aa318f5bSPeter Maydell 
2720aa318f5bSPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2721aa318f5bSPeter Maydell 
2722aa318f5bSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2723aa318f5bSPeter Maydell         TCGv_i32 rn = neon_load_reg(a->vn, pass);
2724aa318f5bSPeter Maydell         TCGv_i32 rd = neon_load_reg(a->vd, pass);
2725aa318f5bSPeter Maydell         opfn(rd, cpu_env, rn, scalar, rd);
2726aa318f5bSPeter Maydell         tcg_temp_free_i32(rn);
2727aa318f5bSPeter Maydell         neon_store_reg(a->vd, pass, rd);
2728aa318f5bSPeter Maydell     }
2729aa318f5bSPeter Maydell     tcg_temp_free_i32(scalar);
2730aa318f5bSPeter Maydell 
2731aa318f5bSPeter Maydell     return true;
2732aa318f5bSPeter Maydell }
2733aa318f5bSPeter Maydell 
2734aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a)
2735aa318f5bSPeter Maydell {
2736aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2737aa318f5bSPeter Maydell         NULL,
2738aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s16,
2739aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s32,
2740aa318f5bSPeter Maydell         NULL,
2741aa318f5bSPeter Maydell     };
2742aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2743aa318f5bSPeter Maydell }
2744aa318f5bSPeter Maydell 
2745aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a)
2746aa318f5bSPeter Maydell {
2747aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2748aa318f5bSPeter Maydell         NULL,
2749aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s16,
2750aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s32,
2751aa318f5bSPeter Maydell         NULL,
2752aa318f5bSPeter Maydell     };
2753aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2754aa318f5bSPeter Maydell }
275577e576a9SPeter Maydell 
275677e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a,
275777e576a9SPeter Maydell                             NeonGenTwoOpWidenFn *opfn,
275877e576a9SPeter Maydell                             NeonGenTwo64OpFn *accfn)
275977e576a9SPeter Maydell {
276077e576a9SPeter Maydell     /*
276177e576a9SPeter Maydell      * Two registers and a scalar, long operations: perform an
276277e576a9SPeter Maydell      * operation on the input elements and the scalar which produces
276377e576a9SPeter Maydell      * a double-width result, and then possibly perform an accumulation
276477e576a9SPeter Maydell      * operation of that result into the destination.
276577e576a9SPeter Maydell      */
276677e576a9SPeter Maydell     TCGv_i32 scalar, rn;
276777e576a9SPeter Maydell     TCGv_i64 rn0_64, rn1_64;
276877e576a9SPeter Maydell 
276977e576a9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
277077e576a9SPeter Maydell         return false;
277177e576a9SPeter Maydell     }
277277e576a9SPeter Maydell 
277377e576a9SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
277477e576a9SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
277577e576a9SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
277677e576a9SPeter Maydell         return false;
277777e576a9SPeter Maydell     }
277877e576a9SPeter Maydell 
277977e576a9SPeter Maydell     if (!opfn) {
278077e576a9SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
278177e576a9SPeter Maydell         return false;
278277e576a9SPeter Maydell     }
278377e576a9SPeter Maydell 
278477e576a9SPeter Maydell     if (a->vd & 1) {
278577e576a9SPeter Maydell         return false;
278677e576a9SPeter Maydell     }
278777e576a9SPeter Maydell 
278877e576a9SPeter Maydell     if (!vfp_access_check(s)) {
278977e576a9SPeter Maydell         return true;
279077e576a9SPeter Maydell     }
279177e576a9SPeter Maydell 
279277e576a9SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
279377e576a9SPeter Maydell 
279477e576a9SPeter Maydell     /* Load all inputs before writing any outputs, in case of overlap */
279577e576a9SPeter Maydell     rn = neon_load_reg(a->vn, 0);
279677e576a9SPeter Maydell     rn0_64 = tcg_temp_new_i64();
279777e576a9SPeter Maydell     opfn(rn0_64, rn, scalar);
279877e576a9SPeter Maydell     tcg_temp_free_i32(rn);
279977e576a9SPeter Maydell 
280077e576a9SPeter Maydell     rn = neon_load_reg(a->vn, 1);
280177e576a9SPeter Maydell     rn1_64 = tcg_temp_new_i64();
280277e576a9SPeter Maydell     opfn(rn1_64, rn, scalar);
280377e576a9SPeter Maydell     tcg_temp_free_i32(rn);
280477e576a9SPeter Maydell     tcg_temp_free_i32(scalar);
280577e576a9SPeter Maydell 
280677e576a9SPeter Maydell     if (accfn) {
280777e576a9SPeter Maydell         TCGv_i64 t64 = tcg_temp_new_i64();
280877e576a9SPeter Maydell         neon_load_reg64(t64, a->vd);
280977e576a9SPeter Maydell         accfn(t64, t64, rn0_64);
281077e576a9SPeter Maydell         neon_store_reg64(t64, a->vd);
281177e576a9SPeter Maydell         neon_load_reg64(t64, a->vd + 1);
281277e576a9SPeter Maydell         accfn(t64, t64, rn1_64);
281377e576a9SPeter Maydell         neon_store_reg64(t64, a->vd + 1);
281477e576a9SPeter Maydell         tcg_temp_free_i64(t64);
281577e576a9SPeter Maydell     } else {
281677e576a9SPeter Maydell         neon_store_reg64(rn0_64, a->vd);
281777e576a9SPeter Maydell         neon_store_reg64(rn1_64, a->vd + 1);
281877e576a9SPeter Maydell     }
281977e576a9SPeter Maydell     tcg_temp_free_i64(rn0_64);
282077e576a9SPeter Maydell     tcg_temp_free_i64(rn1_64);
282177e576a9SPeter Maydell     return true;
282277e576a9SPeter Maydell }
282377e576a9SPeter Maydell 
282477e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a)
282577e576a9SPeter Maydell {
282677e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
282777e576a9SPeter Maydell         NULL,
282877e576a9SPeter Maydell         gen_helper_neon_mull_s16,
282977e576a9SPeter Maydell         gen_mull_s32,
283077e576a9SPeter Maydell         NULL,
283177e576a9SPeter Maydell     };
283277e576a9SPeter Maydell 
283377e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
283477e576a9SPeter Maydell }
283577e576a9SPeter Maydell 
283677e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a)
283777e576a9SPeter Maydell {
283877e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
283977e576a9SPeter Maydell         NULL,
284077e576a9SPeter Maydell         gen_helper_neon_mull_u16,
284177e576a9SPeter Maydell         gen_mull_u32,
284277e576a9SPeter Maydell         NULL,
284377e576a9SPeter Maydell     };
284477e576a9SPeter Maydell 
284577e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
284677e576a9SPeter Maydell }
284777e576a9SPeter Maydell 
284877e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC)                                   \
284977e576a9SPeter Maydell     static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a)     \
285077e576a9SPeter Maydell     {                                                                   \
285177e576a9SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
285277e576a9SPeter Maydell             NULL,                                                       \
285377e576a9SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
285477e576a9SPeter Maydell             gen_##MULL##32,                                             \
285577e576a9SPeter Maydell             NULL,                                                       \
285677e576a9SPeter Maydell         };                                                              \
285777e576a9SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
285877e576a9SPeter Maydell             NULL,                                                       \
285977e576a9SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
286077e576a9SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
286177e576a9SPeter Maydell             NULL,                                                       \
286277e576a9SPeter Maydell         };                                                              \
286377e576a9SPeter Maydell         return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);    \
286477e576a9SPeter Maydell     }
286577e576a9SPeter Maydell 
286677e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add)
286777e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add)
286877e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub)
286977e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub)
287077e576a9SPeter Maydell 
287177e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a)
287277e576a9SPeter Maydell {
287377e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
287477e576a9SPeter Maydell         NULL,
287577e576a9SPeter Maydell         gen_VQDMULL_16,
287677e576a9SPeter Maydell         gen_VQDMULL_32,
287777e576a9SPeter Maydell         NULL,
287877e576a9SPeter Maydell     };
287977e576a9SPeter Maydell 
288077e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
288177e576a9SPeter Maydell }
288277e576a9SPeter Maydell 
288377e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a)
288477e576a9SPeter Maydell {
288577e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
288677e576a9SPeter Maydell         NULL,
288777e576a9SPeter Maydell         gen_VQDMULL_16,
288877e576a9SPeter Maydell         gen_VQDMULL_32,
288977e576a9SPeter Maydell         NULL,
289077e576a9SPeter Maydell     };
289177e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
289277e576a9SPeter Maydell         NULL,
289377e576a9SPeter Maydell         gen_VQDMLAL_acc_16,
289477e576a9SPeter Maydell         gen_VQDMLAL_acc_32,
289577e576a9SPeter Maydell         NULL,
289677e576a9SPeter Maydell     };
289777e576a9SPeter Maydell 
289877e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
289977e576a9SPeter Maydell }
290077e576a9SPeter Maydell 
290177e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a)
290277e576a9SPeter Maydell {
290377e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
290477e576a9SPeter Maydell         NULL,
290577e576a9SPeter Maydell         gen_VQDMULL_16,
290677e576a9SPeter Maydell         gen_VQDMULL_32,
290777e576a9SPeter Maydell         NULL,
290877e576a9SPeter Maydell     };
290977e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
291077e576a9SPeter Maydell         NULL,
291177e576a9SPeter Maydell         gen_VQDMLSL_acc_16,
291277e576a9SPeter Maydell         gen_VQDMLSL_acc_32,
291377e576a9SPeter Maydell         NULL,
291477e576a9SPeter Maydell     };
291577e576a9SPeter Maydell 
291677e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
291777e576a9SPeter Maydell }
29180aad761fSPeter Maydell 
29190aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
29200aad761fSPeter Maydell {
29210aad761fSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
29220aad761fSPeter Maydell         return false;
29230aad761fSPeter Maydell     }
29240aad761fSPeter Maydell 
29250aad761fSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
29260aad761fSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
29270aad761fSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
29280aad761fSPeter Maydell         return false;
29290aad761fSPeter Maydell     }
29300aad761fSPeter Maydell 
29310aad761fSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
29320aad761fSPeter Maydell         return false;
29330aad761fSPeter Maydell     }
29340aad761fSPeter Maydell 
29350aad761fSPeter Maydell     if (a->imm > 7 && !a->q) {
29360aad761fSPeter Maydell         return false;
29370aad761fSPeter Maydell     }
29380aad761fSPeter Maydell 
29390aad761fSPeter Maydell     if (!vfp_access_check(s)) {
29400aad761fSPeter Maydell         return true;
29410aad761fSPeter Maydell     }
29420aad761fSPeter Maydell 
29430aad761fSPeter Maydell     if (!a->q) {
29440aad761fSPeter Maydell         /* Extract 64 bits from <Vm:Vn> */
29450aad761fSPeter Maydell         TCGv_i64 left, right, dest;
29460aad761fSPeter Maydell 
29470aad761fSPeter Maydell         left = tcg_temp_new_i64();
29480aad761fSPeter Maydell         right = tcg_temp_new_i64();
29490aad761fSPeter Maydell         dest = tcg_temp_new_i64();
29500aad761fSPeter Maydell 
29510aad761fSPeter Maydell         neon_load_reg64(right, a->vn);
29520aad761fSPeter Maydell         neon_load_reg64(left, a->vm);
29530aad761fSPeter Maydell         tcg_gen_extract2_i64(dest, right, left, a->imm * 8);
29540aad761fSPeter Maydell         neon_store_reg64(dest, a->vd);
29550aad761fSPeter Maydell 
29560aad761fSPeter Maydell         tcg_temp_free_i64(left);
29570aad761fSPeter Maydell         tcg_temp_free_i64(right);
29580aad761fSPeter Maydell         tcg_temp_free_i64(dest);
29590aad761fSPeter Maydell     } else {
29600aad761fSPeter Maydell         /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */
29610aad761fSPeter Maydell         TCGv_i64 left, middle, right, destleft, destright;
29620aad761fSPeter Maydell 
29630aad761fSPeter Maydell         left = tcg_temp_new_i64();
29640aad761fSPeter Maydell         middle = tcg_temp_new_i64();
29650aad761fSPeter Maydell         right = tcg_temp_new_i64();
29660aad761fSPeter Maydell         destleft = tcg_temp_new_i64();
29670aad761fSPeter Maydell         destright = tcg_temp_new_i64();
29680aad761fSPeter Maydell 
29690aad761fSPeter Maydell         if (a->imm < 8) {
29700aad761fSPeter Maydell             neon_load_reg64(right, a->vn);
29710aad761fSPeter Maydell             neon_load_reg64(middle, a->vn + 1);
29720aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, a->imm * 8);
29730aad761fSPeter Maydell             neon_load_reg64(left, a->vm);
29740aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8);
29750aad761fSPeter Maydell         } else {
29760aad761fSPeter Maydell             neon_load_reg64(right, a->vn + 1);
29770aad761fSPeter Maydell             neon_load_reg64(middle, a->vm);
29780aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8);
29790aad761fSPeter Maydell             neon_load_reg64(left, a->vm + 1);
29800aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8);
29810aad761fSPeter Maydell         }
29820aad761fSPeter Maydell 
29830aad761fSPeter Maydell         neon_store_reg64(destright, a->vd);
29840aad761fSPeter Maydell         neon_store_reg64(destleft, a->vd + 1);
29850aad761fSPeter Maydell 
29860aad761fSPeter Maydell         tcg_temp_free_i64(destright);
29870aad761fSPeter Maydell         tcg_temp_free_i64(destleft);
29880aad761fSPeter Maydell         tcg_temp_free_i64(right);
29890aad761fSPeter Maydell         tcg_temp_free_i64(middle);
29900aad761fSPeter Maydell         tcg_temp_free_i64(left);
29910aad761fSPeter Maydell     }
29920aad761fSPeter Maydell     return true;
29930aad761fSPeter Maydell }
299454e96c74SPeter Maydell 
299554e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
299654e96c74SPeter Maydell {
299754e96c74SPeter Maydell     int n;
299854e96c74SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3, tmp4;
299954e96c74SPeter Maydell     TCGv_ptr ptr1;
300054e96c74SPeter Maydell 
300154e96c74SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
300254e96c74SPeter Maydell         return false;
300354e96c74SPeter Maydell     }
300454e96c74SPeter Maydell 
300554e96c74SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
300654e96c74SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
300754e96c74SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
300854e96c74SPeter Maydell         return false;
300954e96c74SPeter Maydell     }
301054e96c74SPeter Maydell 
301154e96c74SPeter Maydell     if (!vfp_access_check(s)) {
301254e96c74SPeter Maydell         return true;
301354e96c74SPeter Maydell     }
301454e96c74SPeter Maydell 
301554e96c74SPeter Maydell     n = a->len + 1;
301654e96c74SPeter Maydell     if ((a->vn + n) > 32) {
301754e96c74SPeter Maydell         /*
301854e96c74SPeter Maydell          * This is UNPREDICTABLE; we choose to UNDEF to avoid the
301954e96c74SPeter Maydell          * helper function running off the end of the register file.
302054e96c74SPeter Maydell          */
302154e96c74SPeter Maydell         return false;
302254e96c74SPeter Maydell     }
302354e96c74SPeter Maydell     n <<= 3;
302454e96c74SPeter Maydell     if (a->op) {
302554e96c74SPeter Maydell         tmp = neon_load_reg(a->vd, 0);
302654e96c74SPeter Maydell     } else {
302754e96c74SPeter Maydell         tmp = tcg_temp_new_i32();
302854e96c74SPeter Maydell         tcg_gen_movi_i32(tmp, 0);
302954e96c74SPeter Maydell     }
303054e96c74SPeter Maydell     tmp2 = neon_load_reg(a->vm, 0);
303154e96c74SPeter Maydell     ptr1 = vfp_reg_ptr(true, a->vn);
303254e96c74SPeter Maydell     tmp4 = tcg_const_i32(n);
303354e96c74SPeter Maydell     gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4);
303454e96c74SPeter Maydell     tcg_temp_free_i32(tmp);
303554e96c74SPeter Maydell     if (a->op) {
303654e96c74SPeter Maydell         tmp = neon_load_reg(a->vd, 1);
303754e96c74SPeter Maydell     } else {
303854e96c74SPeter Maydell         tmp = tcg_temp_new_i32();
303954e96c74SPeter Maydell         tcg_gen_movi_i32(tmp, 0);
304054e96c74SPeter Maydell     }
304154e96c74SPeter Maydell     tmp3 = neon_load_reg(a->vm, 1);
304254e96c74SPeter Maydell     gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4);
304354e96c74SPeter Maydell     tcg_temp_free_i32(tmp4);
304454e96c74SPeter Maydell     tcg_temp_free_ptr(ptr1);
304554e96c74SPeter Maydell     neon_store_reg(a->vd, 0, tmp2);
304654e96c74SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
304754e96c74SPeter Maydell     tcg_temp_free_i32(tmp);
304854e96c74SPeter Maydell     return true;
304954e96c74SPeter Maydell }
30509aaa23c2SPeter Maydell 
30519aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
30529aaa23c2SPeter Maydell {
30539aaa23c2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
30549aaa23c2SPeter Maydell         return false;
30559aaa23c2SPeter Maydell     }
30569aaa23c2SPeter Maydell 
30579aaa23c2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
30589aaa23c2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
30599aaa23c2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
30609aaa23c2SPeter Maydell         return false;
30619aaa23c2SPeter Maydell     }
30629aaa23c2SPeter Maydell 
30639aaa23c2SPeter Maydell     if (a->vd & a->q) {
30649aaa23c2SPeter Maydell         return false;
30659aaa23c2SPeter Maydell     }
30669aaa23c2SPeter Maydell 
30679aaa23c2SPeter Maydell     if (!vfp_access_check(s)) {
30689aaa23c2SPeter Maydell         return true;
30699aaa23c2SPeter Maydell     }
30709aaa23c2SPeter Maydell 
30719aaa23c2SPeter Maydell     tcg_gen_gvec_dup_mem(a->size, neon_reg_offset(a->vd, 0),
30729aaa23c2SPeter Maydell                          neon_element_offset(a->vm, a->index, a->size),
30739aaa23c2SPeter Maydell                          a->q ? 16 : 8, a->q ? 16 : 8);
30749aaa23c2SPeter Maydell     return true;
30759aaa23c2SPeter Maydell }
3076353d2b85SPeter Maydell 
3077353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
3078353d2b85SPeter Maydell {
3079353d2b85SPeter Maydell     int pass, half;
3080353d2b85SPeter Maydell 
3081353d2b85SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3082353d2b85SPeter Maydell         return false;
3083353d2b85SPeter Maydell     }
3084353d2b85SPeter Maydell 
3085353d2b85SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3086353d2b85SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3087353d2b85SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3088353d2b85SPeter Maydell         return false;
3089353d2b85SPeter Maydell     }
3090353d2b85SPeter Maydell 
3091353d2b85SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3092353d2b85SPeter Maydell         return false;
3093353d2b85SPeter Maydell     }
3094353d2b85SPeter Maydell 
3095353d2b85SPeter Maydell     if (a->size == 3) {
3096353d2b85SPeter Maydell         return false;
3097353d2b85SPeter Maydell     }
3098353d2b85SPeter Maydell 
3099353d2b85SPeter Maydell     if (!vfp_access_check(s)) {
3100353d2b85SPeter Maydell         return true;
3101353d2b85SPeter Maydell     }
3102353d2b85SPeter Maydell 
3103353d2b85SPeter Maydell     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
3104353d2b85SPeter Maydell         TCGv_i32 tmp[2];
3105353d2b85SPeter Maydell 
3106353d2b85SPeter Maydell         for (half = 0; half < 2; half++) {
3107353d2b85SPeter Maydell             tmp[half] = neon_load_reg(a->vm, pass * 2 + half);
3108353d2b85SPeter Maydell             switch (a->size) {
3109353d2b85SPeter Maydell             case 0:
3110353d2b85SPeter Maydell                 tcg_gen_bswap32_i32(tmp[half], tmp[half]);
3111353d2b85SPeter Maydell                 break;
3112353d2b85SPeter Maydell             case 1:
31138ec3de70SPeter Maydell                 gen_swap_half(tmp[half], tmp[half]);
3114353d2b85SPeter Maydell                 break;
3115353d2b85SPeter Maydell             case 2:
3116353d2b85SPeter Maydell                 break;
3117353d2b85SPeter Maydell             default:
3118353d2b85SPeter Maydell                 g_assert_not_reached();
3119353d2b85SPeter Maydell             }
3120353d2b85SPeter Maydell         }
3121353d2b85SPeter Maydell         neon_store_reg(a->vd, pass * 2, tmp[1]);
3122353d2b85SPeter Maydell         neon_store_reg(a->vd, pass * 2 + 1, tmp[0]);
3123353d2b85SPeter Maydell     }
3124353d2b85SPeter Maydell     return true;
3125353d2b85SPeter Maydell }
31266106af3aSPeter Maydell 
31276106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a,
31286106af3aSPeter Maydell                               NeonGenWidenFn *widenfn,
31296106af3aSPeter Maydell                               NeonGenTwo64OpFn *opfn,
31306106af3aSPeter Maydell                               NeonGenTwo64OpFn *accfn)
31316106af3aSPeter Maydell {
31326106af3aSPeter Maydell     /*
31336106af3aSPeter Maydell      * Pairwise long operations: widen both halves of the pair,
31346106af3aSPeter Maydell      * combine the pairs with the opfn, and then possibly accumulate
31356106af3aSPeter Maydell      * into the destination with the accfn.
31366106af3aSPeter Maydell      */
31376106af3aSPeter Maydell     int pass;
31386106af3aSPeter Maydell 
31396106af3aSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
31406106af3aSPeter Maydell         return false;
31416106af3aSPeter Maydell     }
31426106af3aSPeter Maydell 
31436106af3aSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
31446106af3aSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
31456106af3aSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
31466106af3aSPeter Maydell         return false;
31476106af3aSPeter Maydell     }
31486106af3aSPeter Maydell 
31496106af3aSPeter Maydell     if ((a->vd | a->vm) & a->q) {
31506106af3aSPeter Maydell         return false;
31516106af3aSPeter Maydell     }
31526106af3aSPeter Maydell 
31536106af3aSPeter Maydell     if (!widenfn) {
31546106af3aSPeter Maydell         return false;
31556106af3aSPeter Maydell     }
31566106af3aSPeter Maydell 
31576106af3aSPeter Maydell     if (!vfp_access_check(s)) {
31586106af3aSPeter Maydell         return true;
31596106af3aSPeter Maydell     }
31606106af3aSPeter Maydell 
31616106af3aSPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
31626106af3aSPeter Maydell         TCGv_i32 tmp;
31636106af3aSPeter Maydell         TCGv_i64 rm0_64, rm1_64, rd_64;
31646106af3aSPeter Maydell 
31656106af3aSPeter Maydell         rm0_64 = tcg_temp_new_i64();
31666106af3aSPeter Maydell         rm1_64 = tcg_temp_new_i64();
31676106af3aSPeter Maydell         rd_64 = tcg_temp_new_i64();
31686106af3aSPeter Maydell         tmp = neon_load_reg(a->vm, pass * 2);
31696106af3aSPeter Maydell         widenfn(rm0_64, tmp);
31706106af3aSPeter Maydell         tcg_temp_free_i32(tmp);
31716106af3aSPeter Maydell         tmp = neon_load_reg(a->vm, pass * 2 + 1);
31726106af3aSPeter Maydell         widenfn(rm1_64, tmp);
31736106af3aSPeter Maydell         tcg_temp_free_i32(tmp);
31746106af3aSPeter Maydell         opfn(rd_64, rm0_64, rm1_64);
31756106af3aSPeter Maydell         tcg_temp_free_i64(rm0_64);
31766106af3aSPeter Maydell         tcg_temp_free_i64(rm1_64);
31776106af3aSPeter Maydell 
31786106af3aSPeter Maydell         if (accfn) {
31796106af3aSPeter Maydell             TCGv_i64 tmp64 = tcg_temp_new_i64();
31806106af3aSPeter Maydell             neon_load_reg64(tmp64, a->vd + pass);
31816106af3aSPeter Maydell             accfn(rd_64, tmp64, rd_64);
31826106af3aSPeter Maydell             tcg_temp_free_i64(tmp64);
31836106af3aSPeter Maydell         }
31846106af3aSPeter Maydell         neon_store_reg64(rd_64, a->vd + pass);
31856106af3aSPeter Maydell         tcg_temp_free_i64(rd_64);
31866106af3aSPeter Maydell     }
31876106af3aSPeter Maydell     return true;
31886106af3aSPeter Maydell }
31896106af3aSPeter Maydell 
31906106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a)
31916106af3aSPeter Maydell {
31926106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
31936106af3aSPeter Maydell         gen_helper_neon_widen_s8,
31946106af3aSPeter Maydell         gen_helper_neon_widen_s16,
31956106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
31966106af3aSPeter Maydell         NULL,
31976106af3aSPeter Maydell     };
31986106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
31996106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
32006106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
32016106af3aSPeter Maydell         tcg_gen_add_i64,
32026106af3aSPeter Maydell         NULL,
32036106af3aSPeter Maydell     };
32046106af3aSPeter Maydell 
32056106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
32066106af3aSPeter Maydell }
32076106af3aSPeter Maydell 
32086106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a)
32096106af3aSPeter Maydell {
32106106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
32116106af3aSPeter Maydell         gen_helper_neon_widen_u8,
32126106af3aSPeter Maydell         gen_helper_neon_widen_u16,
32136106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
32146106af3aSPeter Maydell         NULL,
32156106af3aSPeter Maydell     };
32166106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
32176106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
32186106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
32196106af3aSPeter Maydell         tcg_gen_add_i64,
32206106af3aSPeter Maydell         NULL,
32216106af3aSPeter Maydell     };
32226106af3aSPeter Maydell 
32236106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
32246106af3aSPeter Maydell }
32256106af3aSPeter Maydell 
32266106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a)
32276106af3aSPeter Maydell {
32286106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
32296106af3aSPeter Maydell         gen_helper_neon_widen_s8,
32306106af3aSPeter Maydell         gen_helper_neon_widen_s16,
32316106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
32326106af3aSPeter Maydell         NULL,
32336106af3aSPeter Maydell     };
32346106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
32356106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
32366106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
32376106af3aSPeter Maydell         tcg_gen_add_i64,
32386106af3aSPeter Maydell         NULL,
32396106af3aSPeter Maydell     };
32406106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
32416106af3aSPeter Maydell         gen_helper_neon_addl_u16,
32426106af3aSPeter Maydell         gen_helper_neon_addl_u32,
32436106af3aSPeter Maydell         tcg_gen_add_i64,
32446106af3aSPeter Maydell         NULL,
32456106af3aSPeter Maydell     };
32466106af3aSPeter Maydell 
32476106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
32486106af3aSPeter Maydell                              accfn[a->size]);
32496106af3aSPeter Maydell }
32506106af3aSPeter Maydell 
32516106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
32526106af3aSPeter Maydell {
32536106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
32546106af3aSPeter Maydell         gen_helper_neon_widen_u8,
32556106af3aSPeter Maydell         gen_helper_neon_widen_u16,
32566106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
32576106af3aSPeter Maydell         NULL,
32586106af3aSPeter Maydell     };
32596106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
32606106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
32616106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
32626106af3aSPeter Maydell         tcg_gen_add_i64,
32636106af3aSPeter Maydell         NULL,
32646106af3aSPeter Maydell     };
32656106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
32666106af3aSPeter Maydell         gen_helper_neon_addl_u16,
32676106af3aSPeter Maydell         gen_helper_neon_addl_u32,
32686106af3aSPeter Maydell         tcg_gen_add_i64,
32696106af3aSPeter Maydell         NULL,
32706106af3aSPeter Maydell     };
32716106af3aSPeter Maydell 
32726106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
32736106af3aSPeter Maydell                              accfn[a->size]);
32746106af3aSPeter Maydell }
3275567663a2SPeter Maydell 
3276567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr);
3277567663a2SPeter Maydell 
3278567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
3279567663a2SPeter Maydell                        ZipFn *fn)
3280567663a2SPeter Maydell {
3281567663a2SPeter Maydell     TCGv_ptr pd, pm;
3282567663a2SPeter Maydell 
3283567663a2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3284567663a2SPeter Maydell         return false;
3285567663a2SPeter Maydell     }
3286567663a2SPeter Maydell 
3287567663a2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3288567663a2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3289567663a2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3290567663a2SPeter Maydell         return false;
3291567663a2SPeter Maydell     }
3292567663a2SPeter Maydell 
3293567663a2SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3294567663a2SPeter Maydell         return false;
3295567663a2SPeter Maydell     }
3296567663a2SPeter Maydell 
3297567663a2SPeter Maydell     if (!fn) {
3298567663a2SPeter Maydell         /* Bad size or size/q combination */
3299567663a2SPeter Maydell         return false;
3300567663a2SPeter Maydell     }
3301567663a2SPeter Maydell 
3302567663a2SPeter Maydell     if (!vfp_access_check(s)) {
3303567663a2SPeter Maydell         return true;
3304567663a2SPeter Maydell     }
3305567663a2SPeter Maydell 
3306567663a2SPeter Maydell     pd = vfp_reg_ptr(true, a->vd);
3307567663a2SPeter Maydell     pm = vfp_reg_ptr(true, a->vm);
3308567663a2SPeter Maydell     fn(pd, pm);
3309567663a2SPeter Maydell     tcg_temp_free_ptr(pd);
3310567663a2SPeter Maydell     tcg_temp_free_ptr(pm);
3311567663a2SPeter Maydell     return true;
3312567663a2SPeter Maydell }
3313567663a2SPeter Maydell 
3314567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a)
3315567663a2SPeter Maydell {
3316567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3317567663a2SPeter Maydell         {
3318567663a2SPeter Maydell             gen_helper_neon_unzip8,
3319567663a2SPeter Maydell             gen_helper_neon_unzip16,
3320567663a2SPeter Maydell             NULL,
3321567663a2SPeter Maydell             NULL,
3322567663a2SPeter Maydell         }, {
3323567663a2SPeter Maydell             gen_helper_neon_qunzip8,
3324567663a2SPeter Maydell             gen_helper_neon_qunzip16,
3325567663a2SPeter Maydell             gen_helper_neon_qunzip32,
3326567663a2SPeter Maydell             NULL,
3327567663a2SPeter Maydell         }
3328567663a2SPeter Maydell     };
3329567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3330567663a2SPeter Maydell }
3331567663a2SPeter Maydell 
3332567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a)
3333567663a2SPeter Maydell {
3334567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3335567663a2SPeter Maydell         {
3336567663a2SPeter Maydell             gen_helper_neon_zip8,
3337567663a2SPeter Maydell             gen_helper_neon_zip16,
3338567663a2SPeter Maydell             NULL,
3339567663a2SPeter Maydell             NULL,
3340567663a2SPeter Maydell         }, {
3341567663a2SPeter Maydell             gen_helper_neon_qzip8,
3342567663a2SPeter Maydell             gen_helper_neon_qzip16,
3343567663a2SPeter Maydell             gen_helper_neon_qzip32,
3344567663a2SPeter Maydell             NULL,
3345567663a2SPeter Maydell         }
3346567663a2SPeter Maydell     };
3347567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3348567663a2SPeter Maydell }
33493882bdacSPeter Maydell 
33503882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a,
33513882bdacSPeter Maydell                      NeonGenNarrowEnvFn *narrowfn)
33523882bdacSPeter Maydell {
33533882bdacSPeter Maydell     TCGv_i64 rm;
33543882bdacSPeter Maydell     TCGv_i32 rd0, rd1;
33553882bdacSPeter Maydell 
33563882bdacSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
33573882bdacSPeter Maydell         return false;
33583882bdacSPeter Maydell     }
33593882bdacSPeter Maydell 
33603882bdacSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
33613882bdacSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
33623882bdacSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
33633882bdacSPeter Maydell         return false;
33643882bdacSPeter Maydell     }
33653882bdacSPeter Maydell 
33663882bdacSPeter Maydell     if (a->vm & 1) {
33673882bdacSPeter Maydell         return false;
33683882bdacSPeter Maydell     }
33693882bdacSPeter Maydell 
33703882bdacSPeter Maydell     if (!narrowfn) {
33713882bdacSPeter Maydell         return false;
33723882bdacSPeter Maydell     }
33733882bdacSPeter Maydell 
33743882bdacSPeter Maydell     if (!vfp_access_check(s)) {
33753882bdacSPeter Maydell         return true;
33763882bdacSPeter Maydell     }
33773882bdacSPeter Maydell 
33783882bdacSPeter Maydell     rm = tcg_temp_new_i64();
33793882bdacSPeter Maydell     rd0 = tcg_temp_new_i32();
33803882bdacSPeter Maydell     rd1 = tcg_temp_new_i32();
33813882bdacSPeter Maydell 
33823882bdacSPeter Maydell     neon_load_reg64(rm, a->vm);
33833882bdacSPeter Maydell     narrowfn(rd0, cpu_env, rm);
33843882bdacSPeter Maydell     neon_load_reg64(rm, a->vm + 1);
33853882bdacSPeter Maydell     narrowfn(rd1, cpu_env, rm);
33863882bdacSPeter Maydell     neon_store_reg(a->vd, 0, rd0);
33873882bdacSPeter Maydell     neon_store_reg(a->vd, 1, rd1);
33883882bdacSPeter Maydell     tcg_temp_free_i64(rm);
33893882bdacSPeter Maydell     return true;
33903882bdacSPeter Maydell }
33913882bdacSPeter Maydell 
33923882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC)                                    \
33933882bdacSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
33943882bdacSPeter Maydell     {                                                           \
33953882bdacSPeter Maydell         static NeonGenNarrowEnvFn * const narrowfn[] = {        \
33963882bdacSPeter Maydell             FUNC##8,                                            \
33973882bdacSPeter Maydell             FUNC##16,                                           \
33983882bdacSPeter Maydell             FUNC##32,                                           \
33993882bdacSPeter Maydell             NULL,                                               \
34003882bdacSPeter Maydell         };                                                      \
34013882bdacSPeter Maydell         return do_vmovn(s, a, narrowfn[a->size]);               \
34023882bdacSPeter Maydell     }
34033882bdacSPeter Maydell 
34043882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u)
34053882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
34063882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
34073882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
3408749e2be3SPeter Maydell 
3409749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
3410749e2be3SPeter Maydell {
3411749e2be3SPeter Maydell     TCGv_i32 rm0, rm1;
3412749e2be3SPeter Maydell     TCGv_i64 rd;
3413749e2be3SPeter Maydell     static NeonGenWidenFn * const widenfns[] = {
3414749e2be3SPeter Maydell         gen_helper_neon_widen_u8,
3415749e2be3SPeter Maydell         gen_helper_neon_widen_u16,
3416749e2be3SPeter Maydell         tcg_gen_extu_i32_i64,
3417749e2be3SPeter Maydell         NULL,
3418749e2be3SPeter Maydell     };
3419749e2be3SPeter Maydell     NeonGenWidenFn *widenfn = widenfns[a->size];
3420749e2be3SPeter Maydell 
3421749e2be3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3422749e2be3SPeter Maydell         return false;
3423749e2be3SPeter Maydell     }
3424749e2be3SPeter Maydell 
3425749e2be3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3426749e2be3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3427749e2be3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3428749e2be3SPeter Maydell         return false;
3429749e2be3SPeter Maydell     }
3430749e2be3SPeter Maydell 
3431749e2be3SPeter Maydell     if (a->vd & 1) {
3432749e2be3SPeter Maydell         return false;
3433749e2be3SPeter Maydell     }
3434749e2be3SPeter Maydell 
3435749e2be3SPeter Maydell     if (!widenfn) {
3436749e2be3SPeter Maydell         return false;
3437749e2be3SPeter Maydell     }
3438749e2be3SPeter Maydell 
3439749e2be3SPeter Maydell     if (!vfp_access_check(s)) {
3440749e2be3SPeter Maydell         return true;
3441749e2be3SPeter Maydell     }
3442749e2be3SPeter Maydell 
3443749e2be3SPeter Maydell     rd = tcg_temp_new_i64();
3444749e2be3SPeter Maydell 
3445749e2be3SPeter Maydell     rm0 = neon_load_reg(a->vm, 0);
3446749e2be3SPeter Maydell     rm1 = neon_load_reg(a->vm, 1);
3447749e2be3SPeter Maydell 
3448749e2be3SPeter Maydell     widenfn(rd, rm0);
3449749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
3450749e2be3SPeter Maydell     neon_store_reg64(rd, a->vd);
3451749e2be3SPeter Maydell     widenfn(rd, rm1);
3452749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
3453749e2be3SPeter Maydell     neon_store_reg64(rd, a->vd + 1);
3454749e2be3SPeter Maydell 
3455749e2be3SPeter Maydell     tcg_temp_free_i64(rd);
3456749e2be3SPeter Maydell     tcg_temp_free_i32(rm0);
3457749e2be3SPeter Maydell     tcg_temp_free_i32(rm1);
3458749e2be3SPeter Maydell     return true;
3459749e2be3SPeter Maydell }
3460654a5173SPeter Maydell 
3461654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
3462654a5173SPeter Maydell {
3463654a5173SPeter Maydell     TCGv_ptr fpst;
3464654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3465654a5173SPeter Maydell 
3466654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3467654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3468654a5173SPeter Maydell         return false;
3469654a5173SPeter Maydell     }
3470654a5173SPeter Maydell 
3471654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3472654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3473654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3474654a5173SPeter Maydell         return false;
3475654a5173SPeter Maydell     }
3476654a5173SPeter Maydell 
3477654a5173SPeter Maydell     if ((a->vm & 1) || (a->size != 1)) {
3478654a5173SPeter Maydell         return false;
3479654a5173SPeter Maydell     }
3480654a5173SPeter Maydell 
3481654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3482654a5173SPeter Maydell         return true;
3483654a5173SPeter Maydell     }
3484654a5173SPeter Maydell 
3485a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3486654a5173SPeter Maydell     ahp = get_ahp_flag();
3487654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 0);
3488654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3489654a5173SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
3490654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
3491654a5173SPeter Maydell     tcg_gen_shli_i32(tmp2, tmp2, 16);
3492654a5173SPeter Maydell     tcg_gen_or_i32(tmp2, tmp2, tmp);
3493654a5173SPeter Maydell     tcg_temp_free_i32(tmp);
3494654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 2);
3495654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3496654a5173SPeter Maydell     tmp3 = neon_load_reg(a->vm, 3);
3497654a5173SPeter Maydell     neon_store_reg(a->vd, 0, tmp2);
3498654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
3499654a5173SPeter Maydell     tcg_gen_shli_i32(tmp3, tmp3, 16);
3500654a5173SPeter Maydell     tcg_gen_or_i32(tmp3, tmp3, tmp);
3501654a5173SPeter Maydell     neon_store_reg(a->vd, 1, tmp3);
3502654a5173SPeter Maydell     tcg_temp_free_i32(tmp);
3503654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3504654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3505654a5173SPeter Maydell 
3506654a5173SPeter Maydell     return true;
3507654a5173SPeter Maydell }
3508654a5173SPeter Maydell 
3509654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
3510654a5173SPeter Maydell {
3511654a5173SPeter Maydell     TCGv_ptr fpst;
3512654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3513654a5173SPeter Maydell 
3514654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3515654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3516654a5173SPeter Maydell         return false;
3517654a5173SPeter Maydell     }
3518654a5173SPeter Maydell 
3519654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3520654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3521654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3522654a5173SPeter Maydell         return false;
3523654a5173SPeter Maydell     }
3524654a5173SPeter Maydell 
3525654a5173SPeter Maydell     if ((a->vd & 1) || (a->size != 1)) {
3526654a5173SPeter Maydell         return false;
3527654a5173SPeter Maydell     }
3528654a5173SPeter Maydell 
3529654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3530654a5173SPeter Maydell         return true;
3531654a5173SPeter Maydell     }
3532654a5173SPeter Maydell 
3533a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3534654a5173SPeter Maydell     ahp = get_ahp_flag();
3535654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
3536654a5173SPeter Maydell     tmp = neon_load_reg(a->vm, 0);
3537654a5173SPeter Maydell     tmp2 = neon_load_reg(a->vm, 1);
3538654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp);
3539654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3540654a5173SPeter Maydell     neon_store_reg(a->vd, 0, tmp3);
3541654a5173SPeter Maydell     tcg_gen_shri_i32(tmp, tmp, 16);
3542654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
3543654a5173SPeter Maydell     neon_store_reg(a->vd, 1, tmp);
3544654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
3545654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp2);
3546654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3547654a5173SPeter Maydell     neon_store_reg(a->vd, 2, tmp3);
3548654a5173SPeter Maydell     tcg_gen_shri_i32(tmp2, tmp2, 16);
3549654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
3550654a5173SPeter Maydell     neon_store_reg(a->vd, 3, tmp2);
3551654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3552654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3553654a5173SPeter Maydell 
3554654a5173SPeter Maydell     return true;
3555654a5173SPeter Maydell }
355675153179SPeter Maydell 
355775153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
355875153179SPeter Maydell {
355975153179SPeter Maydell     int vec_size = a->q ? 16 : 8;
356075153179SPeter Maydell     int rd_ofs = neon_reg_offset(a->vd, 0);
356175153179SPeter Maydell     int rm_ofs = neon_reg_offset(a->vm, 0);
356275153179SPeter Maydell 
356375153179SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
356475153179SPeter Maydell         return false;
356575153179SPeter Maydell     }
356675153179SPeter Maydell 
356775153179SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
356875153179SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
356975153179SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
357075153179SPeter Maydell         return false;
357175153179SPeter Maydell     }
357275153179SPeter Maydell 
357375153179SPeter Maydell     if (a->size == 3) {
357475153179SPeter Maydell         return false;
357575153179SPeter Maydell     }
357675153179SPeter Maydell 
357775153179SPeter Maydell     if ((a->vd | a->vm) & a->q) {
357875153179SPeter Maydell         return false;
357975153179SPeter Maydell     }
358075153179SPeter Maydell 
358175153179SPeter Maydell     if (!vfp_access_check(s)) {
358275153179SPeter Maydell         return true;
358375153179SPeter Maydell     }
358475153179SPeter Maydell 
358575153179SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size);
358675153179SPeter Maydell 
358775153179SPeter Maydell     return true;
358875153179SPeter Maydell }
358975153179SPeter Maydell 
359075153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN)                                  \
359175153179SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
359275153179SPeter Maydell     {                                                           \
359375153179SPeter Maydell         return do_2misc_vec(s, a, FN);                          \
359475153179SPeter Maydell     }
359575153179SPeter Maydell 
359675153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg)
359775153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs)
359875153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0)
359975153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
360075153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
360175153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
360275153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
360375153179SPeter Maydell 
360475153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a)
360575153179SPeter Maydell {
360675153179SPeter Maydell     if (a->size != 0) {
360775153179SPeter Maydell         return false;
360875153179SPeter Maydell     }
360975153179SPeter Maydell     return do_2misc_vec(s, a, tcg_gen_gvec_not);
361075153179SPeter Maydell }
36110b30dd5bSPeter Maydell 
36120b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA)                          \
36130b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
36140b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
36150b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
36160b30dd5bSPeter Maydell     {                                                                   \
36170b30dd5bSPeter Maydell         tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz,        \
36180b30dd5bSPeter Maydell                            DATA, FUNC);                                 \
36190b30dd5bSPeter Maydell     }
36200b30dd5bSPeter Maydell 
36210b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA)                          \
36220b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
36230b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
36240b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
36250b30dd5bSPeter Maydell     {                                                                   \
36260b30dd5bSPeter Maydell         tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC);   \
36270b30dd5bSPeter Maydell     }
36280b30dd5bSPeter Maydell 
36290b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0)
36300b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1)
36310b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0)
36320b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1)
36330b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0)
36340b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0)
36350b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0)
36360b30dd5bSPeter Maydell 
36370b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE)                       \
36380b30dd5bSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
36390b30dd5bSPeter Maydell     {                                                           \
36400b30dd5bSPeter Maydell         if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) {  \
36410b30dd5bSPeter Maydell             return false;                                       \
36420b30dd5bSPeter Maydell         }                                                       \
36430b30dd5bSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                  \
36440b30dd5bSPeter Maydell     }
36450b30dd5bSPeter Maydell 
36460b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0)
36470b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0)
36480b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0)
36490b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
36500b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
36510b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
36520b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
365389668082SPeter Maydell 
365489668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
365589668082SPeter Maydell {
365689668082SPeter Maydell     int pass;
365789668082SPeter Maydell 
365889668082SPeter Maydell     /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
365989668082SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
366089668082SPeter Maydell         return false;
366189668082SPeter Maydell     }
366289668082SPeter Maydell 
366389668082SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
366489668082SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
366589668082SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
366689668082SPeter Maydell         return false;
366789668082SPeter Maydell     }
366889668082SPeter Maydell 
366989668082SPeter Maydell     if (!fn) {
367089668082SPeter Maydell         return false;
367189668082SPeter Maydell     }
367289668082SPeter Maydell 
367389668082SPeter Maydell     if ((a->vd | a->vm) & a->q) {
367489668082SPeter Maydell         return false;
367589668082SPeter Maydell     }
367689668082SPeter Maydell 
367789668082SPeter Maydell     if (!vfp_access_check(s)) {
367889668082SPeter Maydell         return true;
367989668082SPeter Maydell     }
368089668082SPeter Maydell 
368189668082SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
368289668082SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
368389668082SPeter Maydell         fn(tmp, tmp);
368489668082SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
368589668082SPeter Maydell     }
368689668082SPeter Maydell 
368789668082SPeter Maydell     return true;
368889668082SPeter Maydell }
368989668082SPeter Maydell 
369089668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a)
369189668082SPeter Maydell {
369289668082SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
369389668082SPeter Maydell         tcg_gen_bswap32_i32,
369489668082SPeter Maydell         gen_swap_half,
369589668082SPeter Maydell         NULL,
369689668082SPeter Maydell         NULL,
369789668082SPeter Maydell     };
369889668082SPeter Maydell     return do_2misc(s, a, fn[a->size]);
369989668082SPeter Maydell }
370089668082SPeter Maydell 
370189668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a)
370289668082SPeter Maydell {
370389668082SPeter Maydell     if (a->size != 0) {
370489668082SPeter Maydell         return false;
370589668082SPeter Maydell     }
370689668082SPeter Maydell     return do_2misc(s, a, gen_rev16);
370789668082SPeter Maydell }
370884eae770SPeter Maydell 
370984eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a)
371084eae770SPeter Maydell {
371184eae770SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
371284eae770SPeter Maydell         gen_helper_neon_cls_s8,
371384eae770SPeter Maydell         gen_helper_neon_cls_s16,
371484eae770SPeter Maydell         gen_helper_neon_cls_s32,
371584eae770SPeter Maydell         NULL,
371684eae770SPeter Maydell     };
371784eae770SPeter Maydell     return do_2misc(s, a, fn[a->size]);
371884eae770SPeter Maydell }
371984eae770SPeter Maydell 
372084eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm)
372184eae770SPeter Maydell {
372284eae770SPeter Maydell     tcg_gen_clzi_i32(rd, rm, 32);
372384eae770SPeter Maydell }
372484eae770SPeter Maydell 
372584eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a)
372684eae770SPeter Maydell {
372784eae770SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
372884eae770SPeter Maydell         gen_helper_neon_clz_u8,
372984eae770SPeter Maydell         gen_helper_neon_clz_u16,
373084eae770SPeter Maydell         do_VCLZ_32,
373184eae770SPeter Maydell         NULL,
373284eae770SPeter Maydell     };
373384eae770SPeter Maydell     return do_2misc(s, a, fn[a->size]);
373484eae770SPeter Maydell }
373584eae770SPeter Maydell 
373684eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a)
373784eae770SPeter Maydell {
373884eae770SPeter Maydell     if (a->size != 0) {
373984eae770SPeter Maydell         return false;
374084eae770SPeter Maydell     }
374184eae770SPeter Maydell     return do_2misc(s, a, gen_helper_neon_cnt_u8);
374284eae770SPeter Maydell }
374384eae770SPeter Maydell 
374484eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
374584eae770SPeter Maydell {
374684eae770SPeter Maydell     if (a->size != 2) {
374784eae770SPeter Maydell         return false;
374884eae770SPeter Maydell     }
374984eae770SPeter Maydell     /* TODO: FP16 : size == 1 */
375084eae770SPeter Maydell     return do_2misc(s, a, gen_helper_vfp_abss);
375184eae770SPeter Maydell }
375284eae770SPeter Maydell 
375384eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
375484eae770SPeter Maydell {
375584eae770SPeter Maydell     if (a->size != 2) {
375684eae770SPeter Maydell         return false;
375784eae770SPeter Maydell     }
375884eae770SPeter Maydell     /* TODO: FP16 : size == 1 */
375984eae770SPeter Maydell     return do_2misc(s, a, gen_helper_vfp_negs);
376084eae770SPeter Maydell }
376184eae770SPeter Maydell 
376284eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
376384eae770SPeter Maydell {
376484eae770SPeter Maydell     if (a->size != 2) {
376584eae770SPeter Maydell         return false;
376684eae770SPeter Maydell     }
376784eae770SPeter Maydell     return do_2misc(s, a, gen_helper_recpe_u32);
376884eae770SPeter Maydell }
376984eae770SPeter Maydell 
377084eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
377184eae770SPeter Maydell {
377284eae770SPeter Maydell     if (a->size != 2) {
377384eae770SPeter Maydell         return false;
377484eae770SPeter Maydell     }
377584eae770SPeter Maydell     return do_2misc(s, a, gen_helper_rsqrte_u32);
377684eae770SPeter Maydell }
37774936f38aSPeter Maydell 
37784936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \
37794936f38aSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 m)        \
37804936f38aSPeter Maydell     {                                                   \
37814936f38aSPeter Maydell         FUNC(d, cpu_env, m);                            \
37824936f38aSPeter Maydell     }
37834936f38aSPeter Maydell 
37844936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8)
37854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16)
37864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32)
37874936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8)
37884936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16)
37894936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32)
37904936f38aSPeter Maydell 
37914936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a)
37924936f38aSPeter Maydell {
37934936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
37944936f38aSPeter Maydell         gen_VQABS_s8,
37954936f38aSPeter Maydell         gen_VQABS_s16,
37964936f38aSPeter Maydell         gen_VQABS_s32,
37974936f38aSPeter Maydell         NULL,
37984936f38aSPeter Maydell     };
37994936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
38004936f38aSPeter Maydell }
38014936f38aSPeter Maydell 
38024936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a)
38034936f38aSPeter Maydell {
38044936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
38054936f38aSPeter Maydell         gen_VQNEG_s8,
38064936f38aSPeter Maydell         gen_VQNEG_s16,
38074936f38aSPeter Maydell         gen_VQNEG_s32,
38084936f38aSPeter Maydell         NULL,
38094936f38aSPeter Maydell     };
38104936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
38114936f38aSPeter Maydell }
38123e96b205SPeter Maydell 
38133e96b205SPeter Maydell static bool do_2misc_fp(DisasContext *s, arg_2misc *a,
38143e96b205SPeter Maydell                         NeonGenOneSingleOpFn *fn)
38153e96b205SPeter Maydell {
38163e96b205SPeter Maydell     int pass;
38173e96b205SPeter Maydell     TCGv_ptr fpst;
38183e96b205SPeter Maydell 
38193e96b205SPeter Maydell     /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
38203e96b205SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
38213e96b205SPeter Maydell         return false;
38223e96b205SPeter Maydell     }
38233e96b205SPeter Maydell 
38243e96b205SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
38253e96b205SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
38263e96b205SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
38273e96b205SPeter Maydell         return false;
38283e96b205SPeter Maydell     }
38293e96b205SPeter Maydell 
38303e96b205SPeter Maydell     if (a->size != 2) {
38313e96b205SPeter Maydell         /* TODO: FP16 will be the size == 1 case */
38323e96b205SPeter Maydell         return false;
38333e96b205SPeter Maydell     }
38343e96b205SPeter Maydell 
38353e96b205SPeter Maydell     if ((a->vd | a->vm) & a->q) {
38363e96b205SPeter Maydell         return false;
38373e96b205SPeter Maydell     }
38383e96b205SPeter Maydell 
38393e96b205SPeter Maydell     if (!vfp_access_check(s)) {
38403e96b205SPeter Maydell         return true;
38413e96b205SPeter Maydell     }
38423e96b205SPeter Maydell 
3843a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
38443e96b205SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
38453e96b205SPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
38463e96b205SPeter Maydell         fn(tmp, tmp, fpst);
38473e96b205SPeter Maydell         neon_store_reg(a->vd, pass, tmp);
38483e96b205SPeter Maydell     }
38493e96b205SPeter Maydell     tcg_temp_free_ptr(fpst);
38503e96b205SPeter Maydell 
38513e96b205SPeter Maydell     return true;
38523e96b205SPeter Maydell }
38533e96b205SPeter Maydell 
38543e96b205SPeter Maydell #define DO_2MISC_FP(INSN, FUNC)                                 \
38553e96b205SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
38563e96b205SPeter Maydell     {                                                           \
38573e96b205SPeter Maydell         return do_2misc_fp(s, a, FUNC);                         \
38583e96b205SPeter Maydell     }
38593e96b205SPeter Maydell 
38603e96b205SPeter Maydell DO_2MISC_FP(VRECPE_F, gen_helper_recpe_f32)
38613e96b205SPeter Maydell DO_2MISC_FP(VRSQRTE_F, gen_helper_rsqrte_f32)
38623e96b205SPeter Maydell DO_2MISC_FP(VCVT_FS, gen_helper_vfp_sitos)
38633e96b205SPeter Maydell DO_2MISC_FP(VCVT_FU, gen_helper_vfp_uitos)
38643e96b205SPeter Maydell DO_2MISC_FP(VCVT_SF, gen_helper_vfp_tosizs)
38653e96b205SPeter Maydell DO_2MISC_FP(VCVT_UF, gen_helper_vfp_touizs)
38663e96b205SPeter Maydell 
38673e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a)
38683e96b205SPeter Maydell {
38693e96b205SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
38703e96b205SPeter Maydell         return false;
38713e96b205SPeter Maydell     }
38723e96b205SPeter Maydell     return do_2misc_fp(s, a, gen_helper_rints_exact);
38733e96b205SPeter Maydell }
3874baa59323SPeter Maydell 
3875baa59323SPeter Maydell #define WRAP_FP_CMP0_FWD(WRAPNAME, FUNC)                        \
3876baa59323SPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \
3877baa59323SPeter Maydell     {                                                           \
3878baa59323SPeter Maydell         TCGv_i32 zero = tcg_const_i32(0);                       \
3879baa59323SPeter Maydell         FUNC(d, m, zero, fpst);                                 \
3880baa59323SPeter Maydell         tcg_temp_free_i32(zero);                                \
3881baa59323SPeter Maydell     }
3882baa59323SPeter Maydell #define WRAP_FP_CMP0_REV(WRAPNAME, FUNC)                        \
3883baa59323SPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \
3884baa59323SPeter Maydell     {                                                           \
3885baa59323SPeter Maydell         TCGv_i32 zero = tcg_const_i32(0);                       \
3886baa59323SPeter Maydell         FUNC(d, zero, m, fpst);                                 \
3887baa59323SPeter Maydell         tcg_temp_free_i32(zero);                                \
3888baa59323SPeter Maydell     }
3889baa59323SPeter Maydell 
3890baa59323SPeter Maydell #define DO_FP_CMP0(INSN, FUNC, REV)                             \
3891baa59323SPeter Maydell     WRAP_FP_CMP0_##REV(gen_##INSN, FUNC)                        \
3892baa59323SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
3893baa59323SPeter Maydell     {                                                           \
3894baa59323SPeter Maydell         return do_2misc_fp(s, a, gen_##INSN);                   \
3895baa59323SPeter Maydell     }
3896baa59323SPeter Maydell 
3897baa59323SPeter Maydell DO_FP_CMP0(VCGT0_F, gen_helper_neon_cgt_f32, FWD)
3898baa59323SPeter Maydell DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD)
3899baa59323SPeter Maydell DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD)
3900baa59323SPeter Maydell DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV)
3901baa59323SPeter Maydell DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV)
3902128123eaSPeter Maydell 
3903128123eaSPeter Maydell static bool do_vrint(DisasContext *s, arg_2misc *a, int rmode)
3904128123eaSPeter Maydell {
3905128123eaSPeter Maydell     /*
3906128123eaSPeter Maydell      * Handle a VRINT* operation by iterating 32 bits at a time,
3907128123eaSPeter Maydell      * with a specified rounding mode in operation.
3908128123eaSPeter Maydell      */
3909128123eaSPeter Maydell     int pass;
3910128123eaSPeter Maydell     TCGv_ptr fpst;
3911128123eaSPeter Maydell     TCGv_i32 tcg_rmode;
3912128123eaSPeter Maydell 
3913128123eaSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3914128123eaSPeter Maydell         !arm_dc_feature(s, ARM_FEATURE_V8)) {
3915128123eaSPeter Maydell         return false;
3916128123eaSPeter Maydell     }
3917128123eaSPeter Maydell 
3918128123eaSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3919128123eaSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3920128123eaSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3921128123eaSPeter Maydell         return false;
3922128123eaSPeter Maydell     }
3923128123eaSPeter Maydell 
3924128123eaSPeter Maydell     if (a->size != 2) {
3925128123eaSPeter Maydell         /* TODO: FP16 will be the size == 1 case */
3926128123eaSPeter Maydell         return false;
3927128123eaSPeter Maydell     }
3928128123eaSPeter Maydell 
3929128123eaSPeter Maydell     if ((a->vd | a->vm) & a->q) {
3930128123eaSPeter Maydell         return false;
3931128123eaSPeter Maydell     }
3932128123eaSPeter Maydell 
3933128123eaSPeter Maydell     if (!vfp_access_check(s)) {
3934128123eaSPeter Maydell         return true;
3935128123eaSPeter Maydell     }
3936128123eaSPeter Maydell 
3937a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3938128123eaSPeter Maydell     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
3939128123eaSPeter Maydell     gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
3940128123eaSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
3941128123eaSPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
3942128123eaSPeter Maydell         gen_helper_rints(tmp, tmp, fpst);
3943128123eaSPeter Maydell         neon_store_reg(a->vd, pass, tmp);
3944128123eaSPeter Maydell     }
3945128123eaSPeter Maydell     gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
3946128123eaSPeter Maydell     tcg_temp_free_i32(tcg_rmode);
3947128123eaSPeter Maydell     tcg_temp_free_ptr(fpst);
3948128123eaSPeter Maydell 
3949128123eaSPeter Maydell     return true;
3950128123eaSPeter Maydell }
3951128123eaSPeter Maydell 
3952128123eaSPeter Maydell #define DO_VRINT(INSN, RMODE)                                   \
3953128123eaSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
3954128123eaSPeter Maydell     {                                                           \
3955128123eaSPeter Maydell         return do_vrint(s, a, RMODE);                           \
3956128123eaSPeter Maydell     }
3957128123eaSPeter Maydell 
3958128123eaSPeter Maydell DO_VRINT(VRINTN, FPROUNDING_TIEEVEN)
3959128123eaSPeter Maydell DO_VRINT(VRINTA, FPROUNDING_TIEAWAY)
3960128123eaSPeter Maydell DO_VRINT(VRINTZ, FPROUNDING_ZERO)
3961128123eaSPeter Maydell DO_VRINT(VRINTM, FPROUNDING_NEGINF)
3962128123eaSPeter Maydell DO_VRINT(VRINTP, FPROUNDING_POSINF)
3963a183d5fbSPeter Maydell 
3964a183d5fbSPeter Maydell static bool do_vcvt(DisasContext *s, arg_2misc *a, int rmode, bool is_signed)
3965a183d5fbSPeter Maydell {
3966a183d5fbSPeter Maydell     /*
3967a183d5fbSPeter Maydell      * Handle a VCVT* operation by iterating 32 bits at a time,
3968a183d5fbSPeter Maydell      * with a specified rounding mode in operation.
3969a183d5fbSPeter Maydell      */
3970a183d5fbSPeter Maydell     int pass;
3971a183d5fbSPeter Maydell     TCGv_ptr fpst;
3972a183d5fbSPeter Maydell     TCGv_i32 tcg_rmode, tcg_shift;
3973a183d5fbSPeter Maydell 
3974a183d5fbSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3975a183d5fbSPeter Maydell         !arm_dc_feature(s, ARM_FEATURE_V8)) {
3976a183d5fbSPeter Maydell         return false;
3977a183d5fbSPeter Maydell     }
3978a183d5fbSPeter Maydell 
3979a183d5fbSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3980a183d5fbSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3981a183d5fbSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3982a183d5fbSPeter Maydell         return false;
3983a183d5fbSPeter Maydell     }
3984a183d5fbSPeter Maydell 
3985a183d5fbSPeter Maydell     if (a->size != 2) {
3986a183d5fbSPeter Maydell         /* TODO: FP16 will be the size == 1 case */
3987a183d5fbSPeter Maydell         return false;
3988a183d5fbSPeter Maydell     }
3989a183d5fbSPeter Maydell 
3990a183d5fbSPeter Maydell     if ((a->vd | a->vm) & a->q) {
3991a183d5fbSPeter Maydell         return false;
3992a183d5fbSPeter Maydell     }
3993a183d5fbSPeter Maydell 
3994a183d5fbSPeter Maydell     if (!vfp_access_check(s)) {
3995a183d5fbSPeter Maydell         return true;
3996a183d5fbSPeter Maydell     }
3997a183d5fbSPeter Maydell 
3998a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3999a183d5fbSPeter Maydell     tcg_shift = tcg_const_i32(0);
4000a183d5fbSPeter Maydell     tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
4001a183d5fbSPeter Maydell     gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
4002a183d5fbSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
4003a183d5fbSPeter Maydell         TCGv_i32 tmp = neon_load_reg(a->vm, pass);
4004a183d5fbSPeter Maydell         if (is_signed) {
4005a183d5fbSPeter Maydell             gen_helper_vfp_tosls(tmp, tmp, tcg_shift, fpst);
4006a183d5fbSPeter Maydell         } else {
4007a183d5fbSPeter Maydell             gen_helper_vfp_touls(tmp, tmp, tcg_shift, fpst);
4008a183d5fbSPeter Maydell         }
4009a183d5fbSPeter Maydell         neon_store_reg(a->vd, pass, tmp);
4010a183d5fbSPeter Maydell     }
4011a183d5fbSPeter Maydell     gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
4012a183d5fbSPeter Maydell     tcg_temp_free_i32(tcg_rmode);
4013a183d5fbSPeter Maydell     tcg_temp_free_i32(tcg_shift);
4014a183d5fbSPeter Maydell     tcg_temp_free_ptr(fpst);
4015a183d5fbSPeter Maydell 
4016a183d5fbSPeter Maydell     return true;
4017a183d5fbSPeter Maydell }
4018a183d5fbSPeter Maydell 
4019a183d5fbSPeter Maydell #define DO_VCVT(INSN, RMODE, SIGNED)                            \
4020a183d5fbSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
4021a183d5fbSPeter Maydell     {                                                           \
4022a183d5fbSPeter Maydell         return do_vcvt(s, a, RMODE, SIGNED);                    \
4023a183d5fbSPeter Maydell     }
4024a183d5fbSPeter Maydell 
4025a183d5fbSPeter Maydell DO_VCVT(VCVTAU, FPROUNDING_TIEAWAY, false)
4026a183d5fbSPeter Maydell DO_VCVT(VCVTAS, FPROUNDING_TIEAWAY, true)
4027a183d5fbSPeter Maydell DO_VCVT(VCVTNU, FPROUNDING_TIEEVEN, false)
4028a183d5fbSPeter Maydell DO_VCVT(VCVTNS, FPROUNDING_TIEEVEN, true)
4029a183d5fbSPeter Maydell DO_VCVT(VCVTPU, FPROUNDING_POSINF, false)
4030a183d5fbSPeter Maydell DO_VCVT(VCVTPS, FPROUNDING_POSINF, true)
4031a183d5fbSPeter Maydell DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false)
4032a183d5fbSPeter Maydell DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true)
40338ab3a227SPeter Maydell 
40348ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a)
40358ab3a227SPeter Maydell {
40368ab3a227SPeter Maydell     TCGv_i64 rm, rd;
40378ab3a227SPeter Maydell     int pass;
40388ab3a227SPeter Maydell 
40398ab3a227SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
40408ab3a227SPeter Maydell         return false;
40418ab3a227SPeter Maydell     }
40428ab3a227SPeter Maydell 
40438ab3a227SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
40448ab3a227SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
40458ab3a227SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
40468ab3a227SPeter Maydell         return false;
40478ab3a227SPeter Maydell     }
40488ab3a227SPeter Maydell 
40498ab3a227SPeter Maydell     if (a->size != 0) {
40508ab3a227SPeter Maydell         return false;
40518ab3a227SPeter Maydell     }
40528ab3a227SPeter Maydell 
40538ab3a227SPeter Maydell     if ((a->vd | a->vm) & a->q) {
40548ab3a227SPeter Maydell         return false;
40558ab3a227SPeter Maydell     }
40568ab3a227SPeter Maydell 
40578ab3a227SPeter Maydell     if (!vfp_access_check(s)) {
40588ab3a227SPeter Maydell         return true;
40598ab3a227SPeter Maydell     }
40608ab3a227SPeter Maydell 
40618ab3a227SPeter Maydell     rm = tcg_temp_new_i64();
40628ab3a227SPeter Maydell     rd = tcg_temp_new_i64();
40638ab3a227SPeter Maydell     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
40648ab3a227SPeter Maydell         neon_load_reg64(rm, a->vm + pass);
40658ab3a227SPeter Maydell         neon_load_reg64(rd, a->vd + pass);
40668ab3a227SPeter Maydell         neon_store_reg64(rm, a->vd + pass);
40678ab3a227SPeter Maydell         neon_store_reg64(rd, a->vm + pass);
40688ab3a227SPeter Maydell     }
40698ab3a227SPeter Maydell     tcg_temp_free_i64(rm);
40708ab3a227SPeter Maydell     tcg_temp_free_i64(rd);
40718ab3a227SPeter Maydell 
40728ab3a227SPeter Maydell     return true;
40738ab3a227SPeter Maydell }
4074d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
4075d4366190SPeter Maydell {
4076d4366190SPeter Maydell     TCGv_i32 rd, tmp;
4077d4366190SPeter Maydell 
4078d4366190SPeter Maydell     rd = tcg_temp_new_i32();
4079d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
4080d4366190SPeter Maydell 
4081d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 8);
4082d4366190SPeter Maydell     tcg_gen_andi_i32(rd, rd, 0xff00ff00);
4083d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
4084d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
4085d4366190SPeter Maydell 
4086d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 8);
4087d4366190SPeter Maydell     tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
4088d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
4089d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
4090d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
4091d4366190SPeter Maydell 
4092d4366190SPeter Maydell     tcg_temp_free_i32(tmp);
4093d4366190SPeter Maydell     tcg_temp_free_i32(rd);
4094d4366190SPeter Maydell }
4095d4366190SPeter Maydell 
4096d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
4097d4366190SPeter Maydell {
4098d4366190SPeter Maydell     TCGv_i32 rd, tmp;
4099d4366190SPeter Maydell 
4100d4366190SPeter Maydell     rd = tcg_temp_new_i32();
4101d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
4102d4366190SPeter Maydell 
4103d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 16);
4104d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0xffff);
4105d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
4106d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 16);
4107d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xffff0000);
4108d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
4109d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
4110d4366190SPeter Maydell 
4111d4366190SPeter Maydell     tcg_temp_free_i32(tmp);
4112d4366190SPeter Maydell     tcg_temp_free_i32(rd);
4113d4366190SPeter Maydell }
4114d4366190SPeter Maydell 
4115d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a)
4116d4366190SPeter Maydell {
4117d4366190SPeter Maydell     TCGv_i32 tmp, tmp2;
4118d4366190SPeter Maydell     int pass;
4119d4366190SPeter Maydell 
4120d4366190SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
4121d4366190SPeter Maydell         return false;
4122d4366190SPeter Maydell     }
4123d4366190SPeter Maydell 
4124d4366190SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
4125d4366190SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
4126d4366190SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
4127d4366190SPeter Maydell         return false;
4128d4366190SPeter Maydell     }
4129d4366190SPeter Maydell 
4130d4366190SPeter Maydell     if ((a->vd | a->vm) & a->q) {
4131d4366190SPeter Maydell         return false;
4132d4366190SPeter Maydell     }
4133d4366190SPeter Maydell 
4134d4366190SPeter Maydell     if (a->size == 3) {
4135d4366190SPeter Maydell         return false;
4136d4366190SPeter Maydell     }
4137d4366190SPeter Maydell 
4138d4366190SPeter Maydell     if (!vfp_access_check(s)) {
4139d4366190SPeter Maydell         return true;
4140d4366190SPeter Maydell     }
4141d4366190SPeter Maydell 
4142d4366190SPeter Maydell     if (a->size == 2) {
4143d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) {
4144d4366190SPeter Maydell             tmp = neon_load_reg(a->vm, pass);
4145d4366190SPeter Maydell             tmp2 = neon_load_reg(a->vd, pass + 1);
4146d4366190SPeter Maydell             neon_store_reg(a->vm, pass, tmp2);
4147d4366190SPeter Maydell             neon_store_reg(a->vd, pass + 1, tmp);
4148d4366190SPeter Maydell         }
4149d4366190SPeter Maydell     } else {
4150d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
4151d4366190SPeter Maydell             tmp = neon_load_reg(a->vm, pass);
4152d4366190SPeter Maydell             tmp2 = neon_load_reg(a->vd, pass);
4153d4366190SPeter Maydell             if (a->size == 0) {
4154d4366190SPeter Maydell                 gen_neon_trn_u8(tmp, tmp2);
4155d4366190SPeter Maydell             } else {
4156d4366190SPeter Maydell                 gen_neon_trn_u16(tmp, tmp2);
4157d4366190SPeter Maydell             }
4158d4366190SPeter Maydell             neon_store_reg(a->vm, pass, tmp2);
4159d4366190SPeter Maydell             neon_store_reg(a->vd, pass, tmp);
4160d4366190SPeter Maydell         }
4161d4366190SPeter Maydell     }
4162d4366190SPeter Maydell     return true;
4163d4366190SPeter Maydell }
4164