xref: /qemu/target/arm/tcg/translate-neon.c (revision a736cbc303f3c3f79b7b0b09e0dd4e18c8bcf94c)
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
1250f57e09SChetan Pant  * version 2.1 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 
526cf0f240SPeter Maydell static inline int neon_3same_fp_size(DisasContext *s, int x)
536cf0f240SPeter Maydell {
546cf0f240SPeter Maydell     /* Convert 0==fp32, 1==fp16 into a MO_* value */
556cf0f240SPeter Maydell     return MO_32 - x;
566cf0f240SPeter Maydell }
576cf0f240SPeter Maydell 
58625e3dd4SPeter Maydell /* Include the generated Neon decoder */
59139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc"
60139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc"
61139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc"
62afff8de0SPeter Maydell 
636fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
646fb57878SPeter Maydell {
656fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
666fb57878SPeter Maydell 
676fb57878SPeter Maydell     switch (mop) {
686fb57878SPeter Maydell     case MO_UB:
696fb57878SPeter Maydell         tcg_gen_ld8u_i32(var, cpu_env, offset);
706fb57878SPeter Maydell         break;
716fb57878SPeter Maydell     case MO_UW:
726fb57878SPeter Maydell         tcg_gen_ld16u_i32(var, cpu_env, offset);
736fb57878SPeter Maydell         break;
746fb57878SPeter Maydell     case MO_UL:
756fb57878SPeter Maydell         tcg_gen_ld_i32(var, cpu_env, offset);
766fb57878SPeter Maydell         break;
776fb57878SPeter Maydell     default:
786fb57878SPeter Maydell         g_assert_not_reached();
796fb57878SPeter Maydell     }
806fb57878SPeter Maydell }
816fb57878SPeter Maydell 
826fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
836fb57878SPeter Maydell {
846fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
856fb57878SPeter Maydell 
866fb57878SPeter Maydell     switch (mop) {
876fb57878SPeter Maydell     case MO_UB:
886fb57878SPeter Maydell         tcg_gen_ld8u_i64(var, cpu_env, offset);
896fb57878SPeter Maydell         break;
906fb57878SPeter Maydell     case MO_UW:
916fb57878SPeter Maydell         tcg_gen_ld16u_i64(var, cpu_env, offset);
926fb57878SPeter Maydell         break;
936fb57878SPeter Maydell     case MO_UL:
946fb57878SPeter Maydell         tcg_gen_ld32u_i64(var, cpu_env, offset);
956fb57878SPeter Maydell         break;
966fb57878SPeter Maydell     case MO_Q:
976fb57878SPeter Maydell         tcg_gen_ld_i64(var, cpu_env, offset);
986fb57878SPeter Maydell         break;
996fb57878SPeter Maydell     default:
1006fb57878SPeter Maydell         g_assert_not_reached();
1016fb57878SPeter Maydell     }
1026fb57878SPeter Maydell }
1036fb57878SPeter Maydell 
1046fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
1056fb57878SPeter Maydell {
1066fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
1076fb57878SPeter Maydell 
1086fb57878SPeter Maydell     switch (size) {
1096fb57878SPeter Maydell     case MO_8:
1106fb57878SPeter Maydell         tcg_gen_st8_i32(var, cpu_env, offset);
1116fb57878SPeter Maydell         break;
1126fb57878SPeter Maydell     case MO_16:
1136fb57878SPeter Maydell         tcg_gen_st16_i32(var, cpu_env, offset);
1146fb57878SPeter Maydell         break;
1156fb57878SPeter Maydell     case MO_32:
1166fb57878SPeter Maydell         tcg_gen_st_i32(var, cpu_env, offset);
1176fb57878SPeter Maydell         break;
1186fb57878SPeter Maydell     default:
1196fb57878SPeter Maydell         g_assert_not_reached();
1206fb57878SPeter Maydell     }
1216fb57878SPeter Maydell }
1226fb57878SPeter Maydell 
1236fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
1246fb57878SPeter Maydell {
1256fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
1266fb57878SPeter Maydell 
1276fb57878SPeter Maydell     switch (size) {
1286fb57878SPeter Maydell     case MO_8:
1296fb57878SPeter Maydell         tcg_gen_st8_i64(var, cpu_env, offset);
1306fb57878SPeter Maydell         break;
1316fb57878SPeter Maydell     case MO_16:
1326fb57878SPeter Maydell         tcg_gen_st16_i64(var, cpu_env, offset);
1336fb57878SPeter Maydell         break;
1346fb57878SPeter Maydell     case MO_32:
1356fb57878SPeter Maydell         tcg_gen_st32_i64(var, cpu_env, offset);
1366fb57878SPeter Maydell         break;
1376fb57878SPeter Maydell     case MO_64:
1386fb57878SPeter Maydell         tcg_gen_st_i64(var, cpu_env, offset);
1396fb57878SPeter Maydell         break;
1406fb57878SPeter Maydell     default:
1416fb57878SPeter Maydell         g_assert_not_reached();
1426fb57878SPeter Maydell     }
1436fb57878SPeter Maydell }
1446fb57878SPeter Maydell 
145afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
146afff8de0SPeter Maydell {
147afff8de0SPeter Maydell     int opr_sz;
148afff8de0SPeter Maydell     TCGv_ptr fpst;
149afff8de0SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
150afff8de0SPeter Maydell 
151afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
152d186a485SPeter Maydell         || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) {
153afff8de0SPeter Maydell         return false;
154afff8de0SPeter Maydell     }
155afff8de0SPeter Maydell 
156afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
157afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
158afff8de0SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
159afff8de0SPeter Maydell         return false;
160afff8de0SPeter Maydell     }
161afff8de0SPeter Maydell 
162afff8de0SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
163afff8de0SPeter Maydell         return false;
164afff8de0SPeter Maydell     }
165afff8de0SPeter Maydell 
166afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
167afff8de0SPeter Maydell         return true;
168afff8de0SPeter Maydell     }
169afff8de0SPeter Maydell 
170afff8de0SPeter Maydell     opr_sz = (1 + a->q) * 8;
171d186a485SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
172d186a485SPeter Maydell     fn_gvec_ptr = (a->size == MO_16) ?
173d186a485SPeter Maydell         gen_helper_gvec_fcmlah : gen_helper_gvec_fcmlas;
174afff8de0SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
175afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vn),
176afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vm),
177afff8de0SPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
178afff8de0SPeter Maydell                        fn_gvec_ptr);
179afff8de0SPeter Maydell     tcg_temp_free_ptr(fpst);
180afff8de0SPeter Maydell     return true;
181afff8de0SPeter Maydell }
18294d5eb7bSPeter Maydell 
18394d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
18494d5eb7bSPeter Maydell {
18594d5eb7bSPeter Maydell     int opr_sz;
18694d5eb7bSPeter Maydell     TCGv_ptr fpst;
18794d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
18894d5eb7bSPeter Maydell 
18994d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
190d186a485SPeter Maydell         || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) {
19194d5eb7bSPeter Maydell         return false;
19294d5eb7bSPeter Maydell     }
19394d5eb7bSPeter Maydell 
19494d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
19594d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
19694d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
19794d5eb7bSPeter Maydell         return false;
19894d5eb7bSPeter Maydell     }
19994d5eb7bSPeter Maydell 
20094d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
20194d5eb7bSPeter Maydell         return false;
20294d5eb7bSPeter Maydell     }
20394d5eb7bSPeter Maydell 
20494d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
20594d5eb7bSPeter Maydell         return true;
20694d5eb7bSPeter Maydell     }
20794d5eb7bSPeter Maydell 
20894d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
209d186a485SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
210d186a485SPeter Maydell     fn_gvec_ptr = (a->size == MO_16) ?
211d186a485SPeter Maydell         gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds;
21294d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
21394d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
21494d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
21594d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
21694d5eb7bSPeter Maydell                        fn_gvec_ptr);
21794d5eb7bSPeter Maydell     tcg_temp_free_ptr(fpst);
21894d5eb7bSPeter Maydell     return true;
21994d5eb7bSPeter Maydell }
22032da0e33SPeter Maydell 
22132da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
22232da0e33SPeter Maydell {
22332da0e33SPeter Maydell     int opr_sz;
22432da0e33SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
22532da0e33SPeter Maydell 
22632da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
22732da0e33SPeter Maydell         return false;
22832da0e33SPeter Maydell     }
22932da0e33SPeter Maydell 
23032da0e33SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
23132da0e33SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
23232da0e33SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
23332da0e33SPeter Maydell         return false;
23432da0e33SPeter Maydell     }
23532da0e33SPeter Maydell 
23632da0e33SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
23732da0e33SPeter Maydell         return false;
23832da0e33SPeter Maydell     }
23932da0e33SPeter Maydell 
24032da0e33SPeter Maydell     if (!vfp_access_check(s)) {
24132da0e33SPeter Maydell         return true;
24232da0e33SPeter Maydell     }
24332da0e33SPeter Maydell 
24432da0e33SPeter Maydell     opr_sz = (1 + a->q) * 8;
24532da0e33SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
24632da0e33SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
24732da0e33SPeter Maydell                        vfp_reg_offset(1, a->vn),
24832da0e33SPeter Maydell                        vfp_reg_offset(1, a->vm),
24932da0e33SPeter Maydell                        opr_sz, opr_sz, 0, fn_gvec);
25032da0e33SPeter Maydell     return true;
25132da0e33SPeter Maydell }
2529a107e7bSPeter Maydell 
2539a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
2549a107e7bSPeter Maydell {
2559a107e7bSPeter Maydell     int opr_sz;
2569a107e7bSPeter Maydell 
2579a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
2589a107e7bSPeter Maydell         return false;
2599a107e7bSPeter Maydell     }
2609a107e7bSPeter Maydell 
2619a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2629a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2639a107e7bSPeter Maydell         (a->vd & 0x10)) {
2649a107e7bSPeter Maydell         return false;
2659a107e7bSPeter Maydell     }
2669a107e7bSPeter Maydell 
2679a107e7bSPeter Maydell     if (a->vd & a->q) {
2689a107e7bSPeter Maydell         return false;
2699a107e7bSPeter Maydell     }
2709a107e7bSPeter Maydell 
2719a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
2729a107e7bSPeter Maydell         return true;
2739a107e7bSPeter Maydell     }
2749a107e7bSPeter Maydell 
2759a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
2769a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
2779a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
2789a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
2799a107e7bSPeter Maydell                        cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
2809a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
2819a107e7bSPeter Maydell     return true;
2829a107e7bSPeter Maydell }
2837e1b5d61SPeter Maydell 
2847e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
2857e1b5d61SPeter Maydell {
2867e1b5d61SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
2877e1b5d61SPeter Maydell     int opr_sz;
2887e1b5d61SPeter Maydell     TCGv_ptr fpst;
2897e1b5d61SPeter Maydell 
2907e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
2917e1b5d61SPeter Maydell         return false;
2927e1b5d61SPeter Maydell     }
293d186a485SPeter Maydell     if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) {
2947e1b5d61SPeter Maydell         return false;
2957e1b5d61SPeter Maydell     }
2967e1b5d61SPeter Maydell 
2977e1b5d61SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2987e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2997e1b5d61SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
3007e1b5d61SPeter Maydell         return false;
3017e1b5d61SPeter Maydell     }
3027e1b5d61SPeter Maydell 
3037e1b5d61SPeter Maydell     if ((a->vd | a->vn) & a->q) {
3047e1b5d61SPeter Maydell         return false;
3057e1b5d61SPeter Maydell     }
3067e1b5d61SPeter Maydell 
3077e1b5d61SPeter Maydell     if (!vfp_access_check(s)) {
3087e1b5d61SPeter Maydell         return true;
3097e1b5d61SPeter Maydell     }
3107e1b5d61SPeter Maydell 
311d186a485SPeter Maydell     fn_gvec_ptr = (a->size == MO_16) ?
312d186a485SPeter Maydell         gen_helper_gvec_fcmlah_idx : gen_helper_gvec_fcmlas_idx;
3137e1b5d61SPeter Maydell     opr_sz = (1 + a->q) * 8;
314d186a485SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
3157e1b5d61SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
3167e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vn),
3177e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vm),
3187e1b5d61SPeter Maydell                        fpst, opr_sz, opr_sz,
3197e1b5d61SPeter Maydell                        (a->index << 2) | a->rot, fn_gvec_ptr);
3207e1b5d61SPeter Maydell     tcg_temp_free_ptr(fpst);
3217e1b5d61SPeter Maydell     return true;
3227e1b5d61SPeter Maydell }
32335f5d4d1SPeter Maydell 
32435f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
32535f5d4d1SPeter Maydell {
32635f5d4d1SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
32735f5d4d1SPeter Maydell     int opr_sz;
32835f5d4d1SPeter Maydell     TCGv_ptr fpst;
32935f5d4d1SPeter Maydell 
33035f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
33135f5d4d1SPeter Maydell         return false;
33235f5d4d1SPeter Maydell     }
33335f5d4d1SPeter Maydell 
33435f5d4d1SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
33535f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
33635f5d4d1SPeter Maydell         ((a->vd | a->vn) & 0x10)) {
33735f5d4d1SPeter Maydell         return false;
33835f5d4d1SPeter Maydell     }
33935f5d4d1SPeter Maydell 
34035f5d4d1SPeter Maydell     if ((a->vd | a->vn) & a->q) {
34135f5d4d1SPeter Maydell         return false;
34235f5d4d1SPeter Maydell     }
34335f5d4d1SPeter Maydell 
34435f5d4d1SPeter Maydell     if (!vfp_access_check(s)) {
34535f5d4d1SPeter Maydell         return true;
34635f5d4d1SPeter Maydell     }
34735f5d4d1SPeter Maydell 
34835f5d4d1SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
34935f5d4d1SPeter Maydell     opr_sz = (1 + a->q) * 8;
350a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
35135f5d4d1SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
35235f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->vn),
35335f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->rm),
35435f5d4d1SPeter Maydell                        opr_sz, opr_sz, a->index, fn_gvec);
35535f5d4d1SPeter Maydell     tcg_temp_free_ptr(fpst);
35635f5d4d1SPeter Maydell     return true;
35735f5d4d1SPeter Maydell }
358d27e82f7SPeter Maydell 
359d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
360d27e82f7SPeter Maydell {
361d27e82f7SPeter Maydell     int opr_sz;
362d27e82f7SPeter Maydell 
363d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
364d27e82f7SPeter Maydell         return false;
365d27e82f7SPeter Maydell     }
366d27e82f7SPeter Maydell 
367d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
368d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
369d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
370d27e82f7SPeter Maydell         return false;
371d27e82f7SPeter Maydell     }
372d27e82f7SPeter Maydell 
373d27e82f7SPeter Maydell     if (a->vd & a->q) {
374d27e82f7SPeter Maydell         return false;
375d27e82f7SPeter Maydell     }
376d27e82f7SPeter Maydell 
377d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
378d27e82f7SPeter Maydell         return true;
379d27e82f7SPeter Maydell     }
380d27e82f7SPeter Maydell 
381d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
382d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
383d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
384d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
385d27e82f7SPeter Maydell                        cpu_env, opr_sz, opr_sz,
386d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
387d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
388d27e82f7SPeter Maydell     return true;
389d27e82f7SPeter Maydell }
390a27b4630SPeter Maydell 
391a27b4630SPeter Maydell static struct {
392a27b4630SPeter Maydell     int nregs;
393a27b4630SPeter Maydell     int interleave;
394a27b4630SPeter Maydell     int spacing;
395a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
396a27b4630SPeter Maydell     {1, 4, 1},
397a27b4630SPeter Maydell     {1, 4, 2},
398a27b4630SPeter Maydell     {4, 1, 1},
399a27b4630SPeter Maydell     {2, 2, 2},
400a27b4630SPeter Maydell     {1, 3, 1},
401a27b4630SPeter Maydell     {1, 3, 2},
402a27b4630SPeter Maydell     {3, 1, 1},
403a27b4630SPeter Maydell     {1, 1, 1},
404a27b4630SPeter Maydell     {1, 2, 1},
405a27b4630SPeter Maydell     {1, 2, 2},
406a27b4630SPeter Maydell     {2, 1, 1}
407a27b4630SPeter Maydell };
408a27b4630SPeter Maydell 
409a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
410a27b4630SPeter Maydell                                       int stride)
411a27b4630SPeter Maydell {
412a27b4630SPeter Maydell     if (rm != 15) {
413a27b4630SPeter Maydell         TCGv_i32 base;
414a27b4630SPeter Maydell 
415a27b4630SPeter Maydell         base = load_reg(s, rn);
416a27b4630SPeter Maydell         if (rm == 13) {
417a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
418a27b4630SPeter Maydell         } else {
419a27b4630SPeter Maydell             TCGv_i32 index;
420a27b4630SPeter Maydell             index = load_reg(s, rm);
421a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
422a27b4630SPeter Maydell             tcg_temp_free_i32(index);
423a27b4630SPeter Maydell         }
424a27b4630SPeter Maydell         store_reg(s, rn, base);
425a27b4630SPeter Maydell     }
426a27b4630SPeter Maydell }
427a27b4630SPeter Maydell 
428a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
429a27b4630SPeter Maydell {
430a27b4630SPeter Maydell     /* Neon load/store multiple structures */
431a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
432a27b4630SPeter Maydell     MemOp endian = s->be_data;
433a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
434a27b4630SPeter Maydell     int size = a->size;
435a27b4630SPeter Maydell     TCGv_i64 tmp64;
436a27b4630SPeter Maydell     TCGv_i32 addr, tmp;
437a27b4630SPeter Maydell 
438a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
439a27b4630SPeter Maydell         return false;
440a27b4630SPeter Maydell     }
441a27b4630SPeter Maydell 
442a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
443a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
444a27b4630SPeter Maydell         return false;
445a27b4630SPeter Maydell     }
446a27b4630SPeter Maydell     if (a->itype > 10) {
447a27b4630SPeter Maydell         return false;
448a27b4630SPeter Maydell     }
449a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
450a27b4630SPeter Maydell     switch (a->itype & 0xc) {
451a27b4630SPeter Maydell     case 4:
452a27b4630SPeter Maydell         if (a->align >= 2) {
453a27b4630SPeter Maydell             return false;
454a27b4630SPeter Maydell         }
455a27b4630SPeter Maydell         break;
456a27b4630SPeter Maydell     case 8:
457a27b4630SPeter Maydell         if (a->align == 3) {
458a27b4630SPeter Maydell             return false;
459a27b4630SPeter Maydell         }
460a27b4630SPeter Maydell         break;
461a27b4630SPeter Maydell     default:
462a27b4630SPeter Maydell         break;
463a27b4630SPeter Maydell     }
464a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
465a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
466a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
467a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
468a27b4630SPeter Maydell         return false;
469a27b4630SPeter Maydell     }
470a27b4630SPeter Maydell 
471a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
472a27b4630SPeter Maydell         return true;
473a27b4630SPeter Maydell     }
474a27b4630SPeter Maydell 
475a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
476a27b4630SPeter Maydell     if (size == 0) {
477a27b4630SPeter Maydell         endian = MO_LE;
478a27b4630SPeter Maydell     }
479a27b4630SPeter Maydell     /*
480a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
481a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
482a27b4630SPeter Maydell      */
483a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
484a27b4630SPeter Maydell         size = 3;
485a27b4630SPeter Maydell     }
486a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
487a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
488a27b4630SPeter Maydell     tmp = tcg_const_i32(1 << size);
489a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
490a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
491a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
492a27b4630SPeter Maydell             int xs;
493a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
494a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
495a27b4630SPeter Maydell 
496a27b4630SPeter Maydell                 if (a->l) {
497a27b4630SPeter Maydell                     gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
498a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
499a27b4630SPeter Maydell                 } else {
500a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
501a27b4630SPeter Maydell                     gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
502a27b4630SPeter Maydell                 }
503a27b4630SPeter Maydell                 tcg_gen_add_i32(addr, addr, tmp);
504a27b4630SPeter Maydell             }
505a27b4630SPeter Maydell         }
506a27b4630SPeter Maydell     }
507a27b4630SPeter Maydell     tcg_temp_free_i32(addr);
508a27b4630SPeter Maydell     tcg_temp_free_i32(tmp);
509a27b4630SPeter Maydell     tcg_temp_free_i64(tmp64);
510a27b4630SPeter Maydell 
511a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
512a27b4630SPeter Maydell     return true;
513a27b4630SPeter Maydell }
5143698747cSPeter Maydell 
5153698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
5163698747cSPeter Maydell {
5173698747cSPeter Maydell     /* Neon load single structure to all lanes */
5183698747cSPeter Maydell     int reg, stride, vec_size;
5193698747cSPeter Maydell     int vd = a->vd;
5203698747cSPeter Maydell     int size = a->size;
5213698747cSPeter Maydell     int nregs = a->n + 1;
5223698747cSPeter Maydell     TCGv_i32 addr, tmp;
5233698747cSPeter Maydell 
5243698747cSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
5253698747cSPeter Maydell         return false;
5263698747cSPeter Maydell     }
5273698747cSPeter Maydell 
5283698747cSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
5293698747cSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
5303698747cSPeter Maydell         return false;
5313698747cSPeter Maydell     }
5323698747cSPeter Maydell 
5333698747cSPeter Maydell     if (size == 3) {
5343698747cSPeter Maydell         if (nregs != 4 || a->a == 0) {
5353698747cSPeter Maydell             return false;
5363698747cSPeter Maydell         }
5373698747cSPeter Maydell         /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
5383698747cSPeter Maydell         size = 2;
5393698747cSPeter Maydell     }
5403698747cSPeter Maydell     if (nregs == 1 && a->a == 1 && size == 0) {
5413698747cSPeter Maydell         return false;
5423698747cSPeter Maydell     }
5433698747cSPeter Maydell     if (nregs == 3 && a->a == 1) {
5443698747cSPeter Maydell         return false;
5453698747cSPeter Maydell     }
5463698747cSPeter Maydell 
5473698747cSPeter Maydell     if (!vfp_access_check(s)) {
5483698747cSPeter Maydell         return true;
5493698747cSPeter Maydell     }
5503698747cSPeter Maydell 
5513698747cSPeter Maydell     /*
5523698747cSPeter Maydell      * VLD1 to all lanes: T bit indicates how many Dregs to write.
5533698747cSPeter Maydell      * VLD2/3/4 to all lanes: T bit indicates register stride.
5543698747cSPeter Maydell      */
5553698747cSPeter Maydell     stride = a->t ? 2 : 1;
5563698747cSPeter Maydell     vec_size = nregs == 1 ? stride * 8 : 8;
5573698747cSPeter Maydell 
5583698747cSPeter Maydell     tmp = tcg_temp_new_i32();
5593698747cSPeter Maydell     addr = tcg_temp_new_i32();
5603698747cSPeter Maydell     load_reg_var(s, addr, a->rn);
5613698747cSPeter Maydell     for (reg = 0; reg < nregs; reg++) {
5623698747cSPeter Maydell         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
5633698747cSPeter Maydell                         s->be_data | size);
5643698747cSPeter Maydell         if ((vd & 1) && vec_size == 16) {
5653698747cSPeter Maydell             /*
5663698747cSPeter Maydell              * We cannot write 16 bytes at once because the
5673698747cSPeter Maydell              * destination is unaligned.
5683698747cSPeter Maydell              */
569015ee81aSRichard Henderson             tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd),
5703698747cSPeter Maydell                                  8, 8, tmp);
571015ee81aSRichard Henderson             tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1),
572015ee81aSRichard Henderson                              neon_full_reg_offset(vd), 8, 8);
5733698747cSPeter Maydell         } else {
574015ee81aSRichard Henderson             tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd),
5753698747cSPeter Maydell                                  vec_size, vec_size, tmp);
5763698747cSPeter Maydell         }
5773698747cSPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << size);
5783698747cSPeter Maydell         vd += stride;
5793698747cSPeter Maydell     }
5803698747cSPeter Maydell     tcg_temp_free_i32(tmp);
5813698747cSPeter Maydell     tcg_temp_free_i32(addr);
5823698747cSPeter Maydell 
5833698747cSPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
5843698747cSPeter Maydell 
5853698747cSPeter Maydell     return true;
5863698747cSPeter Maydell }
587123ce4e3SPeter Maydell 
588123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
589123ce4e3SPeter Maydell {
590123ce4e3SPeter Maydell     /* Neon load/store single structure to one lane */
591123ce4e3SPeter Maydell     int reg;
592123ce4e3SPeter Maydell     int nregs = a->n + 1;
593123ce4e3SPeter Maydell     int vd = a->vd;
594123ce4e3SPeter Maydell     TCGv_i32 addr, tmp;
595123ce4e3SPeter Maydell 
596123ce4e3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
597123ce4e3SPeter Maydell         return false;
598123ce4e3SPeter Maydell     }
599123ce4e3SPeter Maydell 
600123ce4e3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
601123ce4e3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
602123ce4e3SPeter Maydell         return false;
603123ce4e3SPeter Maydell     }
604123ce4e3SPeter Maydell 
605123ce4e3SPeter Maydell     /* Catch the UNDEF cases. This is unavoidably a bit messy. */
606123ce4e3SPeter Maydell     switch (nregs) {
607123ce4e3SPeter Maydell     case 1:
608123ce4e3SPeter Maydell         if (((a->align & (1 << a->size)) != 0) ||
609*a736cbc3SRichard Henderson             (a->size == 2 && (a->align == 1 || a->align == 2))) {
610123ce4e3SPeter Maydell             return false;
611123ce4e3SPeter Maydell         }
612123ce4e3SPeter Maydell         break;
613123ce4e3SPeter Maydell     case 3:
614123ce4e3SPeter Maydell         if ((a->align & 1) != 0) {
615123ce4e3SPeter Maydell             return false;
616123ce4e3SPeter Maydell         }
617123ce4e3SPeter Maydell         /* fall through */
618123ce4e3SPeter Maydell     case 2:
619123ce4e3SPeter Maydell         if (a->size == 2 && (a->align & 2) != 0) {
620123ce4e3SPeter Maydell             return false;
621123ce4e3SPeter Maydell         }
622123ce4e3SPeter Maydell         break;
623123ce4e3SPeter Maydell     case 4:
624*a736cbc3SRichard Henderson         if (a->size == 2 && a->align == 3) {
625123ce4e3SPeter Maydell             return false;
626123ce4e3SPeter Maydell         }
627123ce4e3SPeter Maydell         break;
628123ce4e3SPeter Maydell     default:
629123ce4e3SPeter Maydell         abort();
630123ce4e3SPeter Maydell     }
631123ce4e3SPeter Maydell     if ((vd + a->stride * (nregs - 1)) > 31) {
632123ce4e3SPeter Maydell         /*
633123ce4e3SPeter Maydell          * Attempts to write off the end of the register file are
634123ce4e3SPeter Maydell          * UNPREDICTABLE; we choose to UNDEF because otherwise we would
635123ce4e3SPeter Maydell          * access off the end of the array that holds the register data.
636123ce4e3SPeter Maydell          */
637123ce4e3SPeter Maydell         return false;
638123ce4e3SPeter Maydell     }
639123ce4e3SPeter Maydell 
640123ce4e3SPeter Maydell     if (!vfp_access_check(s)) {
641123ce4e3SPeter Maydell         return true;
642123ce4e3SPeter Maydell     }
643123ce4e3SPeter Maydell 
644123ce4e3SPeter Maydell     tmp = tcg_temp_new_i32();
645123ce4e3SPeter Maydell     addr = tcg_temp_new_i32();
646123ce4e3SPeter Maydell     load_reg_var(s, addr, a->rn);
647123ce4e3SPeter Maydell     /*
648123ce4e3SPeter Maydell      * TODO: if we implemented alignment exceptions, we should check
649123ce4e3SPeter Maydell      * addr against the alignment encoded in a->align here.
650123ce4e3SPeter Maydell      */
651123ce4e3SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
652123ce4e3SPeter Maydell         if (a->l) {
653123ce4e3SPeter Maydell             gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
654123ce4e3SPeter Maydell                             s->be_data | a->size);
655123ce4e3SPeter Maydell             neon_store_element(vd, a->reg_idx, a->size, tmp);
656123ce4e3SPeter Maydell         } else { /* Store */
657123ce4e3SPeter Maydell             neon_load_element(tmp, vd, a->reg_idx, a->size);
658123ce4e3SPeter Maydell             gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
659123ce4e3SPeter Maydell                             s->be_data | a->size);
660123ce4e3SPeter Maydell         }
661123ce4e3SPeter Maydell         vd += a->stride;
662123ce4e3SPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << a->size);
663123ce4e3SPeter Maydell     }
664123ce4e3SPeter Maydell     tcg_temp_free_i32(addr);
665123ce4e3SPeter Maydell     tcg_temp_free_i32(tmp);
666123ce4e3SPeter Maydell 
667123ce4e3SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
668123ce4e3SPeter Maydell 
669123ce4e3SPeter Maydell     return true;
670123ce4e3SPeter Maydell }
671a4e143acSPeter Maydell 
672a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
673a4e143acSPeter Maydell {
674a4e143acSPeter Maydell     int vec_size = a->q ? 16 : 8;
675015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
676015ee81aSRichard Henderson     int rn_ofs = neon_full_reg_offset(a->vn);
677015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
678a4e143acSPeter Maydell 
679a4e143acSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
680a4e143acSPeter Maydell         return false;
681a4e143acSPeter Maydell     }
682a4e143acSPeter Maydell 
683a4e143acSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
684a4e143acSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
685a4e143acSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
686a4e143acSPeter Maydell         return false;
687a4e143acSPeter Maydell     }
688a4e143acSPeter Maydell 
689a4e143acSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
690a4e143acSPeter Maydell         return false;
691a4e143acSPeter Maydell     }
692a4e143acSPeter Maydell 
693a4e143acSPeter Maydell     if (!vfp_access_check(s)) {
694a4e143acSPeter Maydell         return true;
695a4e143acSPeter Maydell     }
696a4e143acSPeter Maydell 
697a4e143acSPeter Maydell     fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
698a4e143acSPeter Maydell     return true;
699a4e143acSPeter Maydell }
700a4e143acSPeter Maydell 
701a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC)                                            \
702a4e143acSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
703a4e143acSPeter Maydell     {                                                                   \
704a4e143acSPeter Maydell         return do_3same(s, a, FUNC);                                    \
705a4e143acSPeter Maydell     }
706a4e143acSPeter Maydell 
707a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add)
708a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub)
70935a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and)
71035a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc)
71135a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or)
71235a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc)
71335a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor)
7148161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl)
7158161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl)
716c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc)
717c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc)
718c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc)
719c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc)
72035a548edSPeter Maydell 
72135a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */
72235a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3)                               \
72335a548edSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
72435a548edSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
72535a548edSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
72635a548edSPeter Maydell     {                                                                   \
72735a548edSPeter Maydell         tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz);    \
72835a548edSPeter Maydell     }                                                                   \
72935a548edSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
73035a548edSPeter Maydell 
73135a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
73235a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
73335a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
73436b59310SPeter Maydell 
73536b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC)                                    \
73636b59310SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
73736b59310SPeter Maydell     {                                                                   \
73836b59310SPeter Maydell         if (a->size == 3) {                                             \
73936b59310SPeter Maydell             return false;                                               \
74036b59310SPeter Maydell         }                                                               \
74136b59310SPeter Maydell         return do_3same(s, a, FUNC);                                    \
74236b59310SPeter Maydell     }
74336b59310SPeter Maydell 
74436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
74536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
74636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
74736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
7480de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
74927106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla)
75027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls)
7518161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst)
7527715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd)
7537715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba)
7547715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd)
7557715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba)
75602bd0cdbSPeter Maydell 
75702bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND)                                        \
75802bd0cdbSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
75902bd0cdbSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
76002bd0cdbSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
76102bd0cdbSPeter Maydell     {                                                                   \
76202bd0cdbSPeter Maydell         tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
76302bd0cdbSPeter Maydell     }                                                                   \
76402bd0cdbSPeter Maydell     DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
76502bd0cdbSPeter Maydell 
76602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
76702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
76802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
76902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
77002bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
77102bd0cdbSPeter Maydell 
772effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC)                                        \
773effa992fSRichard Henderson     static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,  \
774effa992fSRichard Henderson                          uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)  \
775effa992fSRichard Henderson     {                                                                      \
776effa992fSRichard Henderson         tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \
7770de34fd4SPeter Maydell     }
7780de34fd4SPeter Maydell 
779effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b)
780effa992fSRichard Henderson 
7810de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
7820de34fd4SPeter Maydell {
7830de34fd4SPeter Maydell     if (a->size != 0) {
7840de34fd4SPeter Maydell         return false;
7850de34fd4SPeter Maydell     }
7860de34fd4SPeter Maydell     return do_3same(s, a, gen_VMUL_p_3s);
7870de34fd4SPeter Maydell }
788a0635695SPeter Maydell 
789a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC)                                         \
790a0635695SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
791a0635695SPeter Maydell     {                                                                   \
792a0635695SPeter Maydell         if (!dc_isar_feature(aa32_rdm, s)) {                            \
793a0635695SPeter Maydell             return false;                                               \
794a0635695SPeter Maydell         }                                                               \
795a0635695SPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
796a0635695SPeter Maydell             return false;                                               \
797a0635695SPeter Maydell         }                                                               \
798a0635695SPeter Maydell         return do_3same(s, a, FUNC);                                    \
799a0635695SPeter Maydell     }
800a0635695SPeter Maydell 
801a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc)
802a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc)
80321290edfSPeter Maydell 
804afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC)                                             \
805afc8b7d3SRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
806afc8b7d3SRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
807afc8b7d3SRichard Henderson     {                                                                   \
808afc8b7d3SRichard Henderson         if (!dc_isar_feature(aa32_sha1, s)) {                           \
809afc8b7d3SRichard Henderson             return false;                                               \
810afc8b7d3SRichard Henderson         }                                                               \
811afc8b7d3SRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
81221290edfSPeter Maydell     }
81321290edfSPeter Maydell 
814afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c)
815afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p)
816afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m)
817afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0)
81821290edfSPeter Maydell 
819effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC)                                             \
820effa992fSRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
821effa992fSRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
822effa992fSRichard Henderson     {                                                                   \
823effa992fSRichard Henderson         if (!dc_isar_feature(aa32_sha2, s)) {                           \
824effa992fSRichard Henderson             return false;                                               \
825effa992fSRichard Henderson         }                                                               \
826effa992fSRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
82721290edfSPeter Maydell     }
82821290edfSPeter Maydell 
829effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h)
830effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2)
831effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1)
83235d4352fSPeter Maydell 
83335d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC)                                         \
83435d4352fSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
83535d4352fSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
83635d4352fSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
83735d4352fSPeter Maydell     {                                                                   \
83835d4352fSPeter Maydell         static const GVecGen3 op = { .fni8 = FUNC };                    \
83935d4352fSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op);      \
84035d4352fSPeter Maydell     }                                                                   \
84135d4352fSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
84235d4352fSPeter Maydell 
84335d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC)                                     \
84435d4352fSPeter Maydell     static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)    \
84535d4352fSPeter Maydell     {                                                                   \
84635d4352fSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
84735d4352fSPeter Maydell     }                                                                   \
84835d4352fSPeter Maydell     DO_3SAME_64(INSN, gen_##INSN##_elt)
84935d4352fSPeter Maydell 
85035d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64)
85135d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64)
85235d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64)
85335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64)
85435d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64)
85535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64)
856cb294bcaSPeter Maydell 
857cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC)                                         \
858cb294bcaSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
859cb294bcaSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
860cb294bcaSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
861cb294bcaSPeter Maydell     {                                                                   \
862cb294bcaSPeter Maydell         static const GVecGen3 ops[4] = {                                \
863cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##8 },                      \
864cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##16 },                     \
865cb294bcaSPeter Maydell             { .fni4 = gen_helper_neon_##FUNC##32 },                     \
866cb294bcaSPeter Maydell             { 0 },                                                      \
867cb294bcaSPeter Maydell         };                                                              \
868cb294bcaSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
869cb294bcaSPeter Maydell     }                                                                   \
870cb294bcaSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
871cb294bcaSPeter Maydell     {                                                                   \
872cb294bcaSPeter Maydell         if (a->size > 2) {                                              \
873cb294bcaSPeter Maydell             return false;                                               \
874cb294bcaSPeter Maydell         }                                                               \
875cb294bcaSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
876cb294bcaSPeter Maydell     }
877cb294bcaSPeter Maydell 
8786812dfdcSPeter Maydell /*
8796812dfdcSPeter Maydell  * Some helper functions need to be passed the cpu_env. In order
8806812dfdcSPeter Maydell  * to use those with the gvec APIs like tcg_gen_gvec_3() we need
8816812dfdcSPeter Maydell  * to create wrapper functions whose prototype is a NeonGenTwoOpFn()
8826812dfdcSPeter Maydell  * and which call a NeonGenTwoOpEnvFn().
8836812dfdcSPeter Maydell  */
8846812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC)                                     \
8856812dfdcSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m)            \
8866812dfdcSPeter Maydell     {                                                                   \
8876812dfdcSPeter Maydell         FUNC(d, cpu_env, n, m);                                         \
8886812dfdcSPeter Maydell     }
8896812dfdcSPeter Maydell 
8906812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC)                                     \
8916812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8);        \
8926812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16);      \
8936812dfdcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32);      \
8946812dfdcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
8956812dfdcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
8966812dfdcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
8976812dfdcSPeter Maydell     {                                                                   \
8986812dfdcSPeter Maydell         static const GVecGen3 ops[4] = {                                \
8996812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp8 },                            \
9006812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
9016812dfdcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
9026812dfdcSPeter Maydell             { 0 },                                                      \
9036812dfdcSPeter Maydell         };                                                              \
9046812dfdcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \
9056812dfdcSPeter Maydell     }                                                                   \
9066812dfdcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
9076812dfdcSPeter Maydell     {                                                                   \
9086812dfdcSPeter Maydell         if (a->size > 2) {                                              \
9096812dfdcSPeter Maydell             return false;                                               \
9106812dfdcSPeter Maydell         }                                                               \
9116812dfdcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
9126812dfdcSPeter Maydell     }
9136812dfdcSPeter Maydell 
914cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s)
915cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u)
9168e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s)
9178e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u)
9188e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s)
9198e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u)
9206812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s)
9216812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u)
9226812dfdcSPeter Maydell 
9236812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s)
9246812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u)
9256812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s)
9266812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u)
927059c2398SPeter Maydell 
928059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn)
929059c2398SPeter Maydell {
930059c2398SPeter Maydell     /* Operations handled pairwise 32 bits at a time */
931059c2398SPeter Maydell     TCGv_i32 tmp, tmp2, tmp3;
932059c2398SPeter Maydell 
933059c2398SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
934059c2398SPeter Maydell         return false;
935059c2398SPeter Maydell     }
936059c2398SPeter Maydell 
937059c2398SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
938059c2398SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
939059c2398SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
940059c2398SPeter Maydell         return false;
941059c2398SPeter Maydell     }
942059c2398SPeter Maydell 
943059c2398SPeter Maydell     if (a->size == 3) {
944059c2398SPeter Maydell         return false;
945059c2398SPeter Maydell     }
946059c2398SPeter Maydell 
947059c2398SPeter Maydell     if (!vfp_access_check(s)) {
948059c2398SPeter Maydell         return true;
949059c2398SPeter Maydell     }
950059c2398SPeter Maydell 
951059c2398SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
952059c2398SPeter Maydell 
953059c2398SPeter Maydell     /*
954059c2398SPeter Maydell      * Note that we have to be careful not to clobber the source operands
955059c2398SPeter Maydell      * in the "vm == vd" case by storing the result of the first pass too
956059c2398SPeter Maydell      * early. Since Q is 0 there are always just two passes, so instead
957059c2398SPeter Maydell      * of a complicated loop over each pass we just unroll.
958059c2398SPeter Maydell      */
959a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
960a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
961a712266fSRichard Henderson     tmp3 = tcg_temp_new_i32();
962a712266fSRichard Henderson 
963a712266fSRichard Henderson     read_neon_element32(tmp, a->vn, 0, MO_32);
964a712266fSRichard Henderson     read_neon_element32(tmp2, a->vn, 1, MO_32);
965059c2398SPeter Maydell     fn(tmp, tmp, tmp2);
966059c2398SPeter Maydell 
967a712266fSRichard Henderson     read_neon_element32(tmp3, a->vm, 0, MO_32);
968a712266fSRichard Henderson     read_neon_element32(tmp2, a->vm, 1, MO_32);
969059c2398SPeter Maydell     fn(tmp3, tmp3, tmp2);
970059c2398SPeter Maydell 
971a712266fSRichard Henderson     write_neon_element32(tmp, a->vd, 0, MO_32);
972a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 1, MO_32);
973a712266fSRichard Henderson 
974a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
975a712266fSRichard Henderson     tcg_temp_free_i32(tmp2);
976a712266fSRichard Henderson     tcg_temp_free_i32(tmp3);
977059c2398SPeter Maydell     return true;
978059c2398SPeter Maydell }
979059c2398SPeter Maydell 
980059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func)                                       \
981059c2398SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
982059c2398SPeter Maydell     {                                                                   \
983059c2398SPeter Maydell         static NeonGenTwoOpFn * const fns[] = {                         \
984059c2398SPeter Maydell             gen_helper_neon_##func##8,                                  \
985059c2398SPeter Maydell             gen_helper_neon_##func##16,                                 \
986059c2398SPeter Maydell             gen_helper_neon_##func##32,                                 \
987059c2398SPeter Maydell         };                                                              \
988059c2398SPeter Maydell         if (a->size > 2) {                                              \
989059c2398SPeter Maydell             return false;                                               \
990059c2398SPeter Maydell         }                                                               \
991059c2398SPeter Maydell         return do_3same_pair(s, a, fns[a->size]);                       \
992059c2398SPeter Maydell     }
993059c2398SPeter Maydell 
994059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions.  */
995059c2398SPeter Maydell #define gen_helper_neon_pmax_s32  tcg_gen_smax_i32
996059c2398SPeter Maydell #define gen_helper_neon_pmax_u32  tcg_gen_umax_i32
997059c2398SPeter Maydell #define gen_helper_neon_pmin_s32  tcg_gen_smin_i32
998059c2398SPeter Maydell #define gen_helper_neon_pmin_u32  tcg_gen_umin_i32
999fa22827dSPeter Maydell #define gen_helper_neon_padd_u32  tcg_gen_add_i32
1000059c2398SPeter Maydell 
1001059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s)
1002059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s)
1003059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u)
1004059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u)
1005fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u)
10067ecc28bcSPeter Maydell 
10077ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC)                                    \
10087ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16);    \
10097ecc28bcSPeter Maydell     WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32);    \
10107ecc28bcSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
10117ecc28bcSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
10127ecc28bcSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
10137ecc28bcSPeter Maydell     {                                                                   \
10147ecc28bcSPeter Maydell         static const GVecGen3 ops[2] = {                                \
10157ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp16 },                           \
10167ecc28bcSPeter Maydell             { .fni4 = gen_##INSN##_tramp32 },                           \
10177ecc28bcSPeter Maydell         };                                                              \
10187ecc28bcSPeter Maydell         tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \
10197ecc28bcSPeter Maydell     }                                                                   \
10207ecc28bcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
10217ecc28bcSPeter Maydell     {                                                                   \
10227ecc28bcSPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
10237ecc28bcSPeter Maydell             return false;                                               \
10247ecc28bcSPeter Maydell         }                                                               \
10257ecc28bcSPeter Maydell         return do_3same(s, a, gen_##INSN##_3s);                         \
10267ecc28bcSPeter Maydell     }
10277ecc28bcSPeter Maydell 
10287ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh)
10297ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh)
1030a26a352bSPeter Maydell 
1031e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC)                              \
1032e4a6d4a6SPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
1033a26a352bSPeter Maydell                          uint32_t rn_ofs, uint32_t rm_ofs,              \
1034a26a352bSPeter Maydell                          uint32_t oprsz, uint32_t maxsz)                \
1035a26a352bSPeter Maydell     {                                                                   \
1036e4a6d4a6SPeter Maydell         TCGv_ptr fpst = fpstatus_ptr(FPST);                             \
1037a26a352bSPeter Maydell         tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst,                \
1038a26a352bSPeter Maydell                            oprsz, maxsz, 0, FUNC);                      \
1039a26a352bSPeter Maydell         tcg_temp_free_ptr(fpst);                                        \
1040e4a6d4a6SPeter Maydell     }
1041e4a6d4a6SPeter Maydell 
1042e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC)                                 \
1043e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC)                 \
1044e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC)             \
1045a26a352bSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a)     \
1046a26a352bSPeter Maydell     {                                                                   \
10476cf0f240SPeter Maydell         if (a->size == MO_16) {                                         \
1048e4a6d4a6SPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
1049a26a352bSPeter Maydell                 return false;                                           \
1050a26a352bSPeter Maydell             }                                                           \
1051e4a6d4a6SPeter Maydell             return do_3same(s, a, gen_##INSN##_fp16_3s);                \
1052e4a6d4a6SPeter Maydell         }                                                               \
1053e4a6d4a6SPeter Maydell         return do_3same(s, a, gen_##INSN##_fp32_3s);                    \
1054a26a352bSPeter Maydell     }
1055a26a352bSPeter Maydell 
1056a26a352bSPeter Maydell 
1057e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h)
1058e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h)
1059e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h)
1060e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h)
1061ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h)
1062ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h)
1063ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h)
1064bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h)
1065bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h)
1066e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h)
1067e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h)
1068e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h)
1069e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h)
1070cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h)
1071cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h)
1072ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h)
107340fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h)
1074ab978335SPeter Maydell 
1075e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s)
1076e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h)
1077e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s)
1078e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h)
1079e22705bbSPeter Maydell 
1080d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a)
1081d5fdf9e9SPeter Maydell {
1082d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1083d5fdf9e9SPeter Maydell         return false;
1084d5fdf9e9SPeter Maydell     }
1085d5fdf9e9SPeter Maydell 
10866cf0f240SPeter Maydell     if (a->size == MO_16) {
1087e22705bbSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
1088d5fdf9e9SPeter Maydell             return false;
1089d5fdf9e9SPeter Maydell         }
1090e22705bbSPeter Maydell         return do_3same(s, a, gen_VMAXNM_fp16_3s);
1091e22705bbSPeter Maydell     }
1092e22705bbSPeter Maydell     return do_3same(s, a, gen_VMAXNM_fp32_3s);
1093d5fdf9e9SPeter Maydell }
1094d5fdf9e9SPeter Maydell 
1095d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a)
1096d5fdf9e9SPeter Maydell {
1097d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1098d5fdf9e9SPeter Maydell         return false;
1099d5fdf9e9SPeter Maydell     }
1100d5fdf9e9SPeter Maydell 
11016cf0f240SPeter Maydell     if (a->size == MO_16) {
1102e22705bbSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
1103d5fdf9e9SPeter Maydell             return false;
1104d5fdf9e9SPeter Maydell         }
1105e22705bbSPeter Maydell         return do_3same(s, a, gen_VMINNM_fp16_3s);
1106e22705bbSPeter Maydell     }
1107e22705bbSPeter Maydell     return do_3same(s, a, gen_VMINNM_fp32_3s);
1108d5fdf9e9SPeter Maydell }
1109d5fdf9e9SPeter Maydell 
11101dc587eeSPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a,
11111dc587eeSPeter Maydell                              gen_helper_gvec_3_ptr *fn)
1112ab978335SPeter Maydell {
11131dc587eeSPeter Maydell     /* FP pairwise operations */
1114ab978335SPeter Maydell     TCGv_ptr fpstatus;
1115ab978335SPeter Maydell 
1116ab978335SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1117ab978335SPeter Maydell         return false;
1118ab978335SPeter Maydell     }
1119ab978335SPeter Maydell 
1120ab978335SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1121ab978335SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1122ab978335SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1123ab978335SPeter Maydell         return false;
1124ab978335SPeter Maydell     }
1125ab978335SPeter Maydell 
1126ab978335SPeter Maydell     if (!vfp_access_check(s)) {
1127ab978335SPeter Maydell         return true;
1128ab978335SPeter Maydell     }
1129ab978335SPeter Maydell 
1130ab978335SPeter Maydell     assert(a->q == 0); /* enforced by decode patterns */
1131ab978335SPeter Maydell 
1132ab978335SPeter Maydell 
11336cf0f240SPeter Maydell     fpstatus = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
11341dc587eeSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
11351dc587eeSPeter Maydell                        vfp_reg_offset(1, a->vn),
11361dc587eeSPeter Maydell                        vfp_reg_offset(1, a->vm),
11371dc587eeSPeter Maydell                        fpstatus, 8, 8, 0, fn);
1138ab978335SPeter Maydell     tcg_temp_free_ptr(fpstatus);
1139ab978335SPeter Maydell 
1140ab978335SPeter Maydell     return true;
1141ab978335SPeter Maydell }
1142ab978335SPeter Maydell 
1143ab978335SPeter Maydell /*
1144ab978335SPeter Maydell  * For all the functions using this macro, size == 1 means fp16,
1145ab978335SPeter Maydell  * which is an architecture extension we don't implement yet.
1146ab978335SPeter Maydell  */
1147ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC)                                    \
1148ab978335SPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \
1149ab978335SPeter Maydell     {                                                               \
11506cf0f240SPeter Maydell         if (a->size == MO_16) {                                     \
11511dc587eeSPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {             \
1152ab978335SPeter Maydell                 return false;                                       \
1153ab978335SPeter Maydell             }                                                       \
11541dc587eeSPeter Maydell             return do_3same_fp_pair(s, a, FUNC##h);                 \
11551dc587eeSPeter Maydell         }                                                           \
11561dc587eeSPeter Maydell         return do_3same_fp_pair(s, a, FUNC##s);                     \
1157ab978335SPeter Maydell     }
1158ab978335SPeter Maydell 
11591dc587eeSPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_neon_padd)
11601dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_neon_pmax)
11611dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_neon_pmin)
1162d3c8c736SPeter Maydell 
1163d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
1164d3c8c736SPeter Maydell {
1165d3c8c736SPeter Maydell     /* Handle a 2-reg-shift insn which can be vectorized. */
1166d3c8c736SPeter Maydell     int vec_size = a->q ? 16 : 8;
1167015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
1168015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
1169d3c8c736SPeter Maydell 
1170d3c8c736SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1171d3c8c736SPeter Maydell         return false;
1172d3c8c736SPeter Maydell     }
1173d3c8c736SPeter Maydell 
1174d3c8c736SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1175d3c8c736SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1176d3c8c736SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1177d3c8c736SPeter Maydell         return false;
1178d3c8c736SPeter Maydell     }
1179d3c8c736SPeter Maydell 
1180d3c8c736SPeter Maydell     if ((a->vm | a->vd) & a->q) {
1181d3c8c736SPeter Maydell         return false;
1182d3c8c736SPeter Maydell     }
1183d3c8c736SPeter Maydell 
1184d3c8c736SPeter Maydell     if (!vfp_access_check(s)) {
1185d3c8c736SPeter Maydell         return true;
1186d3c8c736SPeter Maydell     }
1187d3c8c736SPeter Maydell 
1188d3c8c736SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size);
1189d3c8c736SPeter Maydell     return true;
1190d3c8c736SPeter Maydell }
1191d3c8c736SPeter Maydell 
1192d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC)                                              \
1193d3c8c736SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1194d3c8c736SPeter Maydell     {                                                                   \
1195d3c8c736SPeter Maydell         return do_vector_2sh(s, a, FUNC);                               \
1196d3c8c736SPeter Maydell     }                                                                   \
1197d3c8c736SPeter Maydell 
1198d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli)
1199d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli)
1200434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri)
1201434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra)
1202434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra)
1203434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr)
1204434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr)
1205434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra)
1206434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra)
120766432d6bSPeter Maydell 
120866432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a)
120966432d6bSPeter Maydell {
121066432d6bSPeter Maydell     /* Signed shift out of range results in all-sign-bits */
121166432d6bSPeter Maydell     a->shift = MIN(a->shift, (8 << a->size) - 1);
121266432d6bSPeter Maydell     return do_vector_2sh(s, a, tcg_gen_gvec_sari);
121366432d6bSPeter Maydell }
121466432d6bSPeter Maydell 
121566432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
121666432d6bSPeter Maydell                             int64_t shift, uint32_t oprsz, uint32_t maxsz)
121766432d6bSPeter Maydell {
121866432d6bSPeter Maydell     tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0);
121966432d6bSPeter Maydell }
122066432d6bSPeter Maydell 
122166432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a)
122266432d6bSPeter Maydell {
122366432d6bSPeter Maydell     /* Shift out of range is architecturally valid and results in zero. */
122466432d6bSPeter Maydell     if (a->shift >= (8 << a->size)) {
122566432d6bSPeter Maydell         return do_vector_2sh(s, a, gen_zero_rd_2sh);
122666432d6bSPeter Maydell     } else {
122766432d6bSPeter Maydell         return do_vector_2sh(s, a, tcg_gen_gvec_shri);
122866432d6bSPeter Maydell     }
122966432d6bSPeter Maydell }
123037bfce81SPeter Maydell 
123137bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a,
123237bfce81SPeter Maydell                              NeonGenTwo64OpEnvFn *fn)
123337bfce81SPeter Maydell {
123437bfce81SPeter Maydell     /*
123537bfce81SPeter Maydell      * 2-reg-and-shift operations, size == 3 case, where the
123637bfce81SPeter Maydell      * function needs to be passed cpu_env.
123737bfce81SPeter Maydell      */
123837bfce81SPeter Maydell     TCGv_i64 constimm;
123937bfce81SPeter Maydell     int pass;
124037bfce81SPeter Maydell 
124137bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
124237bfce81SPeter Maydell         return false;
124337bfce81SPeter Maydell     }
124437bfce81SPeter Maydell 
124537bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
124637bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
124737bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
124837bfce81SPeter Maydell         return false;
124937bfce81SPeter Maydell     }
125037bfce81SPeter Maydell 
125137bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
125237bfce81SPeter Maydell         return false;
125337bfce81SPeter Maydell     }
125437bfce81SPeter Maydell 
125537bfce81SPeter Maydell     if (!vfp_access_check(s)) {
125637bfce81SPeter Maydell         return true;
125737bfce81SPeter Maydell     }
125837bfce81SPeter Maydell 
125937bfce81SPeter Maydell     /*
126037bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
126137bfce81SPeter Maydell      * by immediate using the variable shift operations.
126237bfce81SPeter Maydell      */
126337bfce81SPeter Maydell     constimm = tcg_const_i64(dup_const(a->size, a->shift));
126437bfce81SPeter Maydell 
126537bfce81SPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
126637bfce81SPeter Maydell         TCGv_i64 tmp = tcg_temp_new_i64();
126737bfce81SPeter Maydell 
12680aa8e700SRichard Henderson         read_neon_element64(tmp, a->vm, pass, MO_64);
126937bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
12700aa8e700SRichard Henderson         write_neon_element64(tmp, a->vd, pass, MO_64);
1271a4f67e18SPeter Maydell         tcg_temp_free_i64(tmp);
127237bfce81SPeter Maydell     }
127337bfce81SPeter Maydell     tcg_temp_free_i64(constimm);
127437bfce81SPeter Maydell     return true;
127537bfce81SPeter Maydell }
127637bfce81SPeter Maydell 
127737bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a,
127837bfce81SPeter Maydell                              NeonGenTwoOpEnvFn *fn)
127937bfce81SPeter Maydell {
128037bfce81SPeter Maydell     /*
128137bfce81SPeter Maydell      * 2-reg-and-shift operations, size < 3 case, where the
128237bfce81SPeter Maydell      * helper needs to be passed cpu_env.
128337bfce81SPeter Maydell      */
1284a712266fSRichard Henderson     TCGv_i32 constimm, tmp;
128537bfce81SPeter Maydell     int pass;
128637bfce81SPeter Maydell 
128737bfce81SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
128837bfce81SPeter Maydell         return false;
128937bfce81SPeter Maydell     }
129037bfce81SPeter Maydell 
129137bfce81SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
129237bfce81SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
129337bfce81SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
129437bfce81SPeter Maydell         return false;
129537bfce81SPeter Maydell     }
129637bfce81SPeter Maydell 
129737bfce81SPeter Maydell     if ((a->vm | a->vd) & a->q) {
129837bfce81SPeter Maydell         return false;
129937bfce81SPeter Maydell     }
130037bfce81SPeter Maydell 
130137bfce81SPeter Maydell     if (!vfp_access_check(s)) {
130237bfce81SPeter Maydell         return true;
130337bfce81SPeter Maydell     }
130437bfce81SPeter Maydell 
130537bfce81SPeter Maydell     /*
130637bfce81SPeter Maydell      * To avoid excessive duplication of ops we implement shift
130737bfce81SPeter Maydell      * by immediate using the variable shift operations.
130837bfce81SPeter Maydell      */
130937bfce81SPeter Maydell     constimm = tcg_const_i32(dup_const(a->size, a->shift));
1310a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
131137bfce81SPeter Maydell 
131237bfce81SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
1313a712266fSRichard Henderson         read_neon_element32(tmp, a->vm, pass, MO_32);
131437bfce81SPeter Maydell         fn(tmp, cpu_env, tmp, constimm);
1315a712266fSRichard Henderson         write_neon_element32(tmp, a->vd, pass, MO_32);
131637bfce81SPeter Maydell     }
1317a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
131837bfce81SPeter Maydell     tcg_temp_free_i32(constimm);
131937bfce81SPeter Maydell     return true;
132037bfce81SPeter Maydell }
132137bfce81SPeter Maydell 
132237bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC)                                       \
132337bfce81SPeter Maydell     static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \
132437bfce81SPeter Maydell     {                                                                   \
132537bfce81SPeter Maydell         return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64);      \
132637bfce81SPeter Maydell     }                                                                   \
132737bfce81SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
132837bfce81SPeter Maydell     {                                                                   \
132937bfce81SPeter Maydell         static NeonGenTwoOpEnvFn * const fns[] = {                      \
133037bfce81SPeter Maydell             gen_helper_neon_##FUNC##8,                                  \
133137bfce81SPeter Maydell             gen_helper_neon_##FUNC##16,                                 \
133237bfce81SPeter Maydell             gen_helper_neon_##FUNC##32,                                 \
133337bfce81SPeter Maydell         };                                                              \
133437bfce81SPeter Maydell         assert(a->size < ARRAY_SIZE(fns));                              \
133537bfce81SPeter Maydell         return do_2shift_env_32(s, a, fns[a->size]);                    \
133637bfce81SPeter Maydell     }
133737bfce81SPeter Maydell 
133837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s)
133937bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u)
134037bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s)
1341712182d3SPeter Maydell 
1342712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
1343712182d3SPeter Maydell                                 NeonGenTwo64OpFn *shiftfn,
1344712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1345712182d3SPeter Maydell {
1346712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size == 3 case */
1347712182d3SPeter Maydell     TCGv_i64 constimm, rm1, rm2;
1348712182d3SPeter Maydell     TCGv_i32 rd;
1349712182d3SPeter Maydell 
1350712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1351712182d3SPeter Maydell         return false;
1352712182d3SPeter Maydell     }
1353712182d3SPeter Maydell 
1354712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1355712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1356712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1357712182d3SPeter Maydell         return false;
1358712182d3SPeter Maydell     }
1359712182d3SPeter Maydell 
1360712182d3SPeter Maydell     if (a->vm & 1) {
1361712182d3SPeter Maydell         return false;
1362712182d3SPeter Maydell     }
1363712182d3SPeter Maydell 
1364712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1365712182d3SPeter Maydell         return true;
1366712182d3SPeter Maydell     }
1367712182d3SPeter Maydell 
1368712182d3SPeter Maydell     /*
1369712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1370712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count.
1371712182d3SPeter Maydell      */
1372712182d3SPeter Maydell     constimm = tcg_const_i64(-a->shift);
1373712182d3SPeter Maydell     rm1 = tcg_temp_new_i64();
1374712182d3SPeter Maydell     rm2 = tcg_temp_new_i64();
1375a712266fSRichard Henderson     rd = tcg_temp_new_i32();
1376712182d3SPeter Maydell 
1377712182d3SPeter Maydell     /* Load both inputs first to avoid potential overwrite if rm == rd */
13780aa8e700SRichard Henderson     read_neon_element64(rm1, a->vm, 0, MO_64);
13790aa8e700SRichard Henderson     read_neon_element64(rm2, a->vm, 1, MO_64);
1380712182d3SPeter Maydell 
1381712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1382712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm1);
1383a712266fSRichard Henderson     write_neon_element32(rd, a->vd, 0, MO_32);
1384712182d3SPeter Maydell 
1385712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1386712182d3SPeter Maydell     narrowfn(rd, cpu_env, rm2);
1387a712266fSRichard Henderson     write_neon_element32(rd, a->vd, 1, MO_32);
1388712182d3SPeter Maydell 
1389a712266fSRichard Henderson     tcg_temp_free_i32(rd);
1390712182d3SPeter Maydell     tcg_temp_free_i64(rm1);
1391712182d3SPeter Maydell     tcg_temp_free_i64(rm2);
1392712182d3SPeter Maydell     tcg_temp_free_i64(constimm);
1393712182d3SPeter Maydell 
1394712182d3SPeter Maydell     return true;
1395712182d3SPeter Maydell }
1396712182d3SPeter Maydell 
1397712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
1398712182d3SPeter Maydell                                 NeonGenTwoOpFn *shiftfn,
1399712182d3SPeter Maydell                                 NeonGenNarrowEnvFn *narrowfn)
1400712182d3SPeter Maydell {
1401712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size < 3 case */
1402712182d3SPeter Maydell     TCGv_i32 constimm, rm1, rm2, rm3, rm4;
1403712182d3SPeter Maydell     TCGv_i64 rtmp;
1404712182d3SPeter Maydell     uint32_t imm;
1405712182d3SPeter Maydell 
1406712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1407712182d3SPeter Maydell         return false;
1408712182d3SPeter Maydell     }
1409712182d3SPeter Maydell 
1410712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1411712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1412712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1413712182d3SPeter Maydell         return false;
1414712182d3SPeter Maydell     }
1415712182d3SPeter Maydell 
1416712182d3SPeter Maydell     if (a->vm & 1) {
1417712182d3SPeter Maydell         return false;
1418712182d3SPeter Maydell     }
1419712182d3SPeter Maydell 
1420712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1421712182d3SPeter Maydell         return true;
1422712182d3SPeter Maydell     }
1423712182d3SPeter Maydell 
1424712182d3SPeter Maydell     /*
1425712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1426712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count
1427712182d3SPeter Maydell      * duplicated into each lane of the immediate value.
1428712182d3SPeter Maydell      */
1429712182d3SPeter Maydell     if (a->size == 1) {
1430712182d3SPeter Maydell         imm = (uint16_t)(-a->shift);
1431712182d3SPeter Maydell         imm |= imm << 16;
1432712182d3SPeter Maydell     } else {
1433712182d3SPeter Maydell         /* size == 2 */
1434712182d3SPeter Maydell         imm = -a->shift;
1435712182d3SPeter Maydell     }
1436712182d3SPeter Maydell     constimm = tcg_const_i32(imm);
1437712182d3SPeter Maydell 
1438712182d3SPeter Maydell     /* Load all inputs first to avoid potential overwrite */
1439a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
1440a712266fSRichard Henderson     rm2 = tcg_temp_new_i32();
1441a712266fSRichard Henderson     rm3 = tcg_temp_new_i32();
1442a712266fSRichard Henderson     rm4 = tcg_temp_new_i32();
1443a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 0, MO_32);
1444a712266fSRichard Henderson     read_neon_element32(rm2, a->vm, 1, MO_32);
1445a712266fSRichard Henderson     read_neon_element32(rm3, a->vm, 2, MO_32);
1446a712266fSRichard Henderson     read_neon_element32(rm4, a->vm, 3, MO_32);
1447712182d3SPeter Maydell     rtmp = tcg_temp_new_i64();
1448712182d3SPeter Maydell 
1449712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1450712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1451712182d3SPeter Maydell 
1452712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
1453712182d3SPeter Maydell     tcg_temp_free_i32(rm2);
1454712182d3SPeter Maydell 
1455712182d3SPeter Maydell     narrowfn(rm1, cpu_env, rtmp);
1456a712266fSRichard Henderson     write_neon_element32(rm1, a->vd, 0, MO_32);
1457a712266fSRichard Henderson     tcg_temp_free_i32(rm1);
1458712182d3SPeter Maydell 
1459712182d3SPeter Maydell     shiftfn(rm3, rm3, constimm);
1460712182d3SPeter Maydell     shiftfn(rm4, rm4, constimm);
1461712182d3SPeter Maydell     tcg_temp_free_i32(constimm);
1462712182d3SPeter Maydell 
1463712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
1464712182d3SPeter Maydell     tcg_temp_free_i32(rm4);
1465712182d3SPeter Maydell 
1466712182d3SPeter Maydell     narrowfn(rm3, cpu_env, rtmp);
1467712182d3SPeter Maydell     tcg_temp_free_i64(rtmp);
1468a712266fSRichard Henderson     write_neon_element32(rm3, a->vd, 1, MO_32);
1469a712266fSRichard Henderson     tcg_temp_free_i32(rm3);
1470712182d3SPeter Maydell     return true;
1471712182d3SPeter Maydell }
1472712182d3SPeter Maydell 
1473712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC)                               \
1474712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1475712182d3SPeter Maydell     {                                                                   \
1476712182d3SPeter Maydell         return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC);             \
1477712182d3SPeter Maydell     }
1478712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC)                               \
1479712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1480712182d3SPeter Maydell     {                                                                   \
1481712182d3SPeter Maydell         return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC);             \
1482712182d3SPeter Maydell     }
1483712182d3SPeter Maydell 
1484712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1485712182d3SPeter Maydell {
1486712182d3SPeter Maydell     tcg_gen_extrl_i64_i32(dest, src);
1487712182d3SPeter Maydell }
1488712182d3SPeter Maydell 
1489712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1490712182d3SPeter Maydell {
1491712182d3SPeter Maydell     gen_helper_neon_narrow_u16(dest, src);
1492712182d3SPeter Maydell }
1493712182d3SPeter Maydell 
1494712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
1495712182d3SPeter Maydell {
1496712182d3SPeter Maydell     gen_helper_neon_narrow_u8(dest, src);
1497712182d3SPeter Maydell }
1498712182d3SPeter Maydell 
1499712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32)
1500712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16)
1501712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8)
1502712182d3SPeter Maydell 
1503712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32)
1504712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16)
1505712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8)
1506712182d3SPeter Maydell 
1507712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32)
1508712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16)
1509712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8)
1510712182d3SPeter Maydell 
1511712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32)
1512712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16)
1513712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8)
1514b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32)
1515b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16)
1516b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8)
1517b4a3a77bSPeter Maydell 
1518b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32)
1519b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16)
1520b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8)
1521b4a3a77bSPeter Maydell 
1522b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32)
1523b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16)
1524b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8)
1525b4a3a77bSPeter Maydell 
1526b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32)
1527b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16)
1528b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8)
1529968bf842SPeter Maydell 
1530968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
1531968bf842SPeter Maydell                          NeonGenWidenFn *widenfn, bool u)
1532968bf842SPeter Maydell {
1533968bf842SPeter Maydell     TCGv_i64 tmp;
1534968bf842SPeter Maydell     TCGv_i32 rm0, rm1;
1535968bf842SPeter Maydell     uint64_t widen_mask = 0;
1536968bf842SPeter Maydell 
1537968bf842SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1538968bf842SPeter Maydell         return false;
1539968bf842SPeter Maydell     }
1540968bf842SPeter Maydell 
1541968bf842SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1542968bf842SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1543968bf842SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1544968bf842SPeter Maydell         return false;
1545968bf842SPeter Maydell     }
1546968bf842SPeter Maydell 
1547968bf842SPeter Maydell     if (a->vd & 1) {
1548968bf842SPeter Maydell         return false;
1549968bf842SPeter Maydell     }
1550968bf842SPeter Maydell 
1551968bf842SPeter Maydell     if (!vfp_access_check(s)) {
1552968bf842SPeter Maydell         return true;
1553968bf842SPeter Maydell     }
1554968bf842SPeter Maydell 
1555968bf842SPeter Maydell     /*
1556968bf842SPeter Maydell      * This is a widen-and-shift operation. The shift is always less
1557968bf842SPeter Maydell      * than the width of the source type, so after widening the input
1558968bf842SPeter Maydell      * vector we can simply shift the whole 64-bit widened register,
1559968bf842SPeter Maydell      * and then clear the potential overflow bits resulting from left
1560968bf842SPeter Maydell      * bits of the narrow input appearing as right bits of the left
1561968bf842SPeter Maydell      * neighbour narrow input. Calculate a mask of bits to clear.
1562968bf842SPeter Maydell      */
1563968bf842SPeter Maydell     if ((a->shift != 0) && (a->size < 2 || u)) {
1564968bf842SPeter Maydell         int esize = 8 << a->size;
1565968bf842SPeter Maydell         widen_mask = MAKE_64BIT_MASK(0, esize);
1566968bf842SPeter Maydell         widen_mask >>= esize - a->shift;
1567968bf842SPeter Maydell         widen_mask = dup_const(a->size + 1, widen_mask);
1568968bf842SPeter Maydell     }
1569968bf842SPeter Maydell 
1570a712266fSRichard Henderson     rm0 = tcg_temp_new_i32();
1571a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
1572a712266fSRichard Henderson     read_neon_element32(rm0, a->vm, 0, MO_32);
1573a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 1, MO_32);
1574968bf842SPeter Maydell     tmp = tcg_temp_new_i64();
1575968bf842SPeter Maydell 
1576968bf842SPeter Maydell     widenfn(tmp, rm0);
15779593a398SPeter Maydell     tcg_temp_free_i32(rm0);
1578968bf842SPeter Maydell     if (a->shift != 0) {
1579968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1580968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1581968bf842SPeter Maydell     }
15820aa8e700SRichard Henderson     write_neon_element64(tmp, a->vd, 0, MO_64);
1583968bf842SPeter Maydell 
1584968bf842SPeter Maydell     widenfn(tmp, rm1);
15859593a398SPeter Maydell     tcg_temp_free_i32(rm1);
1586968bf842SPeter Maydell     if (a->shift != 0) {
1587968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1588968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1589968bf842SPeter Maydell     }
15900aa8e700SRichard Henderson     write_neon_element64(tmp, a->vd, 1, MO_64);
1591968bf842SPeter Maydell     tcg_temp_free_i64(tmp);
1592968bf842SPeter Maydell     return true;
1593968bf842SPeter Maydell }
1594968bf842SPeter Maydell 
1595968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a)
1596968bf842SPeter Maydell {
1597448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1598968bf842SPeter Maydell         gen_helper_neon_widen_s8,
1599968bf842SPeter Maydell         gen_helper_neon_widen_s16,
1600968bf842SPeter Maydell         tcg_gen_ext_i32_i64,
1601968bf842SPeter Maydell     };
1602968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], false);
1603968bf842SPeter Maydell }
1604968bf842SPeter Maydell 
1605968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
1606968bf842SPeter Maydell {
1607448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1608968bf842SPeter Maydell         gen_helper_neon_widen_u8,
1609968bf842SPeter Maydell         gen_helper_neon_widen_u16,
1610968bf842SPeter Maydell         tcg_gen_extu_i32_i64,
1611968bf842SPeter Maydell     };
1612968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], true);
1613968bf842SPeter Maydell }
16143da26f11SPeter Maydell 
16153da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
16167b959c58SPeter Maydell                       gen_helper_gvec_2_ptr *fn)
16173da26f11SPeter Maydell {
16183da26f11SPeter Maydell     /* FP operations in 2-reg-and-shift group */
16197b959c58SPeter Maydell     int vec_size = a->q ? 16 : 8;
1620015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
1621015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
16227b959c58SPeter Maydell     TCGv_ptr fpst;
16233da26f11SPeter Maydell 
16243da26f11SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
16253da26f11SPeter Maydell         return false;
16263da26f11SPeter Maydell     }
16273da26f11SPeter Maydell 
16280ae715c6SPeter Maydell     if (a->size == MO_16) {
16297b959c58SPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
16307b959c58SPeter Maydell             return false;
16317b959c58SPeter Maydell         }
16327b959c58SPeter Maydell     }
16337b959c58SPeter Maydell 
16343da26f11SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
16353da26f11SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
16363da26f11SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
16373da26f11SPeter Maydell         return false;
16383da26f11SPeter Maydell     }
16393da26f11SPeter Maydell 
16403da26f11SPeter Maydell     if ((a->vm | a->vd) & a->q) {
16413da26f11SPeter Maydell         return false;
16423da26f11SPeter Maydell     }
16433da26f11SPeter Maydell 
16443da26f11SPeter Maydell     if (!vfp_access_check(s)) {
16453da26f11SPeter Maydell         return true;
16463da26f11SPeter Maydell     }
16473da26f11SPeter Maydell 
16480ae715c6SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
16497b959c58SPeter Maydell     tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn);
16507b959c58SPeter Maydell     tcg_temp_free_ptr(fpst);
16513da26f11SPeter Maydell     return true;
16523da26f11SPeter Maydell }
16533da26f11SPeter Maydell 
16543da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC)                                           \
16553da26f11SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
16563da26f11SPeter Maydell     {                                                                   \
16573da26f11SPeter Maydell         return do_fp_2sh(s, a, FUNC);                                   \
16583da26f11SPeter Maydell     }
16593da26f11SPeter Maydell 
16607b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf)
16617b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf)
16627b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs)
16637b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu)
16642c35a39eSPeter Maydell 
166524018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh)
166624018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh)
166724018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs)
166824018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu)
166924018cf3SPeter Maydell 
16702c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
16712c35a39eSPeter Maydell {
16722c35a39eSPeter Maydell     /*
16732c35a39eSPeter Maydell      * Expand the encoded constant.
16742c35a39eSPeter Maydell      * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
16752c35a39eSPeter Maydell      * We choose to not special-case this and will behave as if a
16762c35a39eSPeter Maydell      * valid constant encoding of 0 had been given.
16772c35a39eSPeter Maydell      * cmode = 15 op = 1 must UNDEF; we assume decode has handled that.
16782c35a39eSPeter Maydell      */
16792c35a39eSPeter Maydell     switch (cmode) {
16802c35a39eSPeter Maydell     case 0: case 1:
16812c35a39eSPeter Maydell         /* no-op */
16822c35a39eSPeter Maydell         break;
16832c35a39eSPeter Maydell     case 2: case 3:
16842c35a39eSPeter Maydell         imm <<= 8;
16852c35a39eSPeter Maydell         break;
16862c35a39eSPeter Maydell     case 4: case 5:
16872c35a39eSPeter Maydell         imm <<= 16;
16882c35a39eSPeter Maydell         break;
16892c35a39eSPeter Maydell     case 6: case 7:
16902c35a39eSPeter Maydell         imm <<= 24;
16912c35a39eSPeter Maydell         break;
16922c35a39eSPeter Maydell     case 8: case 9:
16932c35a39eSPeter Maydell         imm |= imm << 16;
16942c35a39eSPeter Maydell         break;
16952c35a39eSPeter Maydell     case 10: case 11:
16962c35a39eSPeter Maydell         imm = (imm << 8) | (imm << 24);
16972c35a39eSPeter Maydell         break;
16982c35a39eSPeter Maydell     case 12:
16992c35a39eSPeter Maydell         imm = (imm << 8) | 0xff;
17002c35a39eSPeter Maydell         break;
17012c35a39eSPeter Maydell     case 13:
17022c35a39eSPeter Maydell         imm = (imm << 16) | 0xffff;
17032c35a39eSPeter Maydell         break;
17042c35a39eSPeter Maydell     case 14:
17052c35a39eSPeter Maydell         if (op) {
17062c35a39eSPeter Maydell             /*
17072c35a39eSPeter Maydell              * This is the only case where the top and bottom 32 bits
17082c35a39eSPeter Maydell              * of the encoded constant differ.
17092c35a39eSPeter Maydell              */
17102c35a39eSPeter Maydell             uint64_t imm64 = 0;
17112c35a39eSPeter Maydell             int n;
17122c35a39eSPeter Maydell 
17132c35a39eSPeter Maydell             for (n = 0; n < 8; n++) {
17142c35a39eSPeter Maydell                 if (imm & (1 << n)) {
17152c35a39eSPeter Maydell                     imm64 |= (0xffULL << (n * 8));
17162c35a39eSPeter Maydell                 }
17172c35a39eSPeter Maydell             }
17182c35a39eSPeter Maydell             return imm64;
17192c35a39eSPeter Maydell         }
17202c35a39eSPeter Maydell         imm |= (imm << 8) | (imm << 16) | (imm << 24);
17212c35a39eSPeter Maydell         break;
17222c35a39eSPeter Maydell     case 15:
17232c35a39eSPeter Maydell         imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
17242c35a39eSPeter Maydell             | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
17252c35a39eSPeter Maydell         break;
17262c35a39eSPeter Maydell     }
17272c35a39eSPeter Maydell     if (op) {
17282c35a39eSPeter Maydell         imm = ~imm;
17292c35a39eSPeter Maydell     }
17302c35a39eSPeter Maydell     return dup_const(MO_32, imm);
17312c35a39eSPeter Maydell }
17322c35a39eSPeter Maydell 
17332c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
17342c35a39eSPeter Maydell                         GVecGen2iFn *fn)
17352c35a39eSPeter Maydell {
17362c35a39eSPeter Maydell     uint64_t imm;
17372c35a39eSPeter Maydell     int reg_ofs, vec_size;
17382c35a39eSPeter Maydell 
17392c35a39eSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
17402c35a39eSPeter Maydell         return false;
17412c35a39eSPeter Maydell     }
17422c35a39eSPeter Maydell 
17432c35a39eSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
17442c35a39eSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
17452c35a39eSPeter Maydell         return false;
17462c35a39eSPeter Maydell     }
17472c35a39eSPeter Maydell 
17482c35a39eSPeter Maydell     if (a->vd & a->q) {
17492c35a39eSPeter Maydell         return false;
17502c35a39eSPeter Maydell     }
17512c35a39eSPeter Maydell 
17522c35a39eSPeter Maydell     if (!vfp_access_check(s)) {
17532c35a39eSPeter Maydell         return true;
17542c35a39eSPeter Maydell     }
17552c35a39eSPeter Maydell 
1756015ee81aSRichard Henderson     reg_ofs = neon_full_reg_offset(a->vd);
17572c35a39eSPeter Maydell     vec_size = a->q ? 16 : 8;
17582c35a39eSPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
17592c35a39eSPeter Maydell 
17602c35a39eSPeter Maydell     fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size);
17612c35a39eSPeter Maydell     return true;
17622c35a39eSPeter Maydell }
17632c35a39eSPeter Maydell 
17642c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs,
17652c35a39eSPeter Maydell                         int64_t c, uint32_t oprsz, uint32_t maxsz)
17662c35a39eSPeter Maydell {
17672c35a39eSPeter Maydell     tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
17682c35a39eSPeter Maydell }
17692c35a39eSPeter Maydell 
17702c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a)
17712c35a39eSPeter Maydell {
17722c35a39eSPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
17732c35a39eSPeter Maydell     GVecGen2iFn *fn;
17742c35a39eSPeter Maydell 
17752c35a39eSPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
17762c35a39eSPeter Maydell         /* for op=1, the imm will be inverted, so BIC becomes AND. */
17772c35a39eSPeter Maydell         fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
17782c35a39eSPeter Maydell     } else {
17792c35a39eSPeter Maydell         /* There is one unallocated cmode/op combination in this space */
17802c35a39eSPeter Maydell         if (a->cmode == 15 && a->op == 1) {
17812c35a39eSPeter Maydell             return false;
17822c35a39eSPeter Maydell         }
17832c35a39eSPeter Maydell         fn = gen_VMOV_1r;
17842c35a39eSPeter Maydell     }
17852c35a39eSPeter Maydell     return do_1reg_imm(s, a, fn);
17862c35a39eSPeter Maydell }
1787b28be095SPeter Maydell 
1788b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
1789b28be095SPeter Maydell                            NeonGenWidenFn *widenfn,
1790b28be095SPeter Maydell                            NeonGenTwo64OpFn *opfn,
17918aab18a2SRichard Henderson                            int src1_mop, int src2_mop)
1792b28be095SPeter Maydell {
1793b28be095SPeter Maydell     /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */
1794b28be095SPeter Maydell     TCGv_i64 rn0_64, rn1_64, rm_64;
1795b28be095SPeter Maydell 
1796b28be095SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1797b28be095SPeter Maydell         return false;
1798b28be095SPeter Maydell     }
1799b28be095SPeter Maydell 
1800b28be095SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1801b28be095SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1802b28be095SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1803b28be095SPeter Maydell         return false;
1804b28be095SPeter Maydell     }
1805b28be095SPeter Maydell 
18068aab18a2SRichard Henderson     if (!opfn) {
1807b28be095SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
1808b28be095SPeter Maydell         return false;
1809b28be095SPeter Maydell     }
1810b28be095SPeter Maydell 
18118aab18a2SRichard Henderson     if ((a->vd & 1) || (src1_mop == MO_Q && (a->vn & 1))) {
1812b28be095SPeter Maydell         return false;
1813b28be095SPeter Maydell     }
1814b28be095SPeter Maydell 
1815b28be095SPeter Maydell     if (!vfp_access_check(s)) {
1816b28be095SPeter Maydell         return true;
1817b28be095SPeter Maydell     }
1818b28be095SPeter Maydell 
1819b28be095SPeter Maydell     rn0_64 = tcg_temp_new_i64();
1820b28be095SPeter Maydell     rn1_64 = tcg_temp_new_i64();
1821b28be095SPeter Maydell     rm_64 = tcg_temp_new_i64();
1822b28be095SPeter Maydell 
18238aab18a2SRichard Henderson     if (src1_mop >= 0) {
18248aab18a2SRichard Henderson         read_neon_element64(rn0_64, a->vn, 0, src1_mop);
1825b28be095SPeter Maydell     } else {
1826a712266fSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
1827a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, 0, MO_32);
1828b28be095SPeter Maydell         widenfn(rn0_64, tmp);
1829b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1830b28be095SPeter Maydell     }
18318aab18a2SRichard Henderson     if (src2_mop >= 0) {
18328aab18a2SRichard Henderson         read_neon_element64(rm_64, a->vm, 0, src2_mop);
18338aab18a2SRichard Henderson     } else {
18348aab18a2SRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
18358aab18a2SRichard Henderson         read_neon_element32(tmp, a->vm, 0, MO_32);
18368aab18a2SRichard Henderson         widenfn(rm_64, tmp);
18378aab18a2SRichard Henderson         tcg_temp_free_i32(tmp);
18388aab18a2SRichard Henderson     }
1839b28be095SPeter Maydell 
1840b28be095SPeter Maydell     opfn(rn0_64, rn0_64, rm_64);
1841b28be095SPeter Maydell 
1842b28be095SPeter Maydell     /*
1843b28be095SPeter Maydell      * Load second pass inputs before storing the first pass result, to
1844b28be095SPeter Maydell      * avoid incorrect results if a narrow input overlaps with the result.
1845b28be095SPeter Maydell      */
18468aab18a2SRichard Henderson     if (src1_mop >= 0) {
18478aab18a2SRichard Henderson         read_neon_element64(rn1_64, a->vn, 1, src1_mop);
1848b28be095SPeter Maydell     } else {
1849a712266fSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
1850a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, 1, MO_32);
1851b28be095SPeter Maydell         widenfn(rn1_64, tmp);
1852b28be095SPeter Maydell         tcg_temp_free_i32(tmp);
1853b28be095SPeter Maydell     }
18548aab18a2SRichard Henderson     if (src2_mop >= 0) {
18558aab18a2SRichard Henderson         read_neon_element64(rm_64, a->vm, 1, src2_mop);
18568aab18a2SRichard Henderson     } else {
18578aab18a2SRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
18588aab18a2SRichard Henderson         read_neon_element32(tmp, a->vm, 1, MO_32);
18598aab18a2SRichard Henderson         widenfn(rm_64, tmp);
18608aab18a2SRichard Henderson         tcg_temp_free_i32(tmp);
18618aab18a2SRichard Henderson     }
1862b28be095SPeter Maydell 
18630aa8e700SRichard Henderson     write_neon_element64(rn0_64, a->vd, 0, MO_64);
1864b28be095SPeter Maydell 
1865b28be095SPeter Maydell     opfn(rn1_64, rn1_64, rm_64);
18660aa8e700SRichard Henderson     write_neon_element64(rn1_64, a->vd, 1, MO_64);
1867b28be095SPeter Maydell 
1868b28be095SPeter Maydell     tcg_temp_free_i64(rn0_64);
1869b28be095SPeter Maydell     tcg_temp_free_i64(rn1_64);
1870b28be095SPeter Maydell     tcg_temp_free_i64(rm_64);
1871b28be095SPeter Maydell 
1872b28be095SPeter Maydell     return true;
1873b28be095SPeter Maydell }
1874b28be095SPeter Maydell 
18758aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN)                        \
1876b28be095SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
1877b28be095SPeter Maydell     {                                                                   \
1878b28be095SPeter Maydell         static NeonGenWidenFn * const widenfn[] = {                     \
1879b28be095SPeter Maydell             gen_helper_neon_widen_##S##8,                               \
1880b28be095SPeter Maydell             gen_helper_neon_widen_##S##16,                              \
18818aab18a2SRichard Henderson             NULL, NULL,                                                 \
1882b28be095SPeter Maydell         };                                                              \
1883b28be095SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
1884b28be095SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
1885b28be095SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
1886b28be095SPeter Maydell             tcg_gen_##OP##_i64,                                         \
1887b28be095SPeter Maydell             NULL,                                                       \
1888b28be095SPeter Maydell         };                                                              \
18898aab18a2SRichard Henderson         int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1;          \
18908aab18a2SRichard Henderson         return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size],   \
18918aab18a2SRichard Henderson                               SRC1WIDE ? MO_Q : narrow_mop,             \
18928aab18a2SRichard Henderson                               narrow_mop);                              \
1893b28be095SPeter Maydell     }
1894b28be095SPeter Maydell 
18958aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN)
18968aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0)
18978aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN)
18988aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0)
18998aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN)
19008aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0)
19018aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN)
19028aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0)
19030fa1ab03SPeter Maydell 
19040fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
19050fa1ab03SPeter Maydell                          NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn)
19060fa1ab03SPeter Maydell {
19070fa1ab03SPeter Maydell     /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */
19080fa1ab03SPeter Maydell     TCGv_i64 rn_64, rm_64;
19090fa1ab03SPeter Maydell     TCGv_i32 rd0, rd1;
19100fa1ab03SPeter Maydell 
19110fa1ab03SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
19120fa1ab03SPeter Maydell         return false;
19130fa1ab03SPeter Maydell     }
19140fa1ab03SPeter Maydell 
19150fa1ab03SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
19160fa1ab03SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
19170fa1ab03SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
19180fa1ab03SPeter Maydell         return false;
19190fa1ab03SPeter Maydell     }
19200fa1ab03SPeter Maydell 
19210fa1ab03SPeter Maydell     if (!opfn || !narrowfn) {
19220fa1ab03SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
19230fa1ab03SPeter Maydell         return false;
19240fa1ab03SPeter Maydell     }
19250fa1ab03SPeter Maydell 
19260fa1ab03SPeter Maydell     if ((a->vn | a->vm) & 1) {
19270fa1ab03SPeter Maydell         return false;
19280fa1ab03SPeter Maydell     }
19290fa1ab03SPeter Maydell 
19300fa1ab03SPeter Maydell     if (!vfp_access_check(s)) {
19310fa1ab03SPeter Maydell         return true;
19320fa1ab03SPeter Maydell     }
19330fa1ab03SPeter Maydell 
19340fa1ab03SPeter Maydell     rn_64 = tcg_temp_new_i64();
19350fa1ab03SPeter Maydell     rm_64 = tcg_temp_new_i64();
19360fa1ab03SPeter Maydell     rd0 = tcg_temp_new_i32();
19370fa1ab03SPeter Maydell     rd1 = tcg_temp_new_i32();
19380fa1ab03SPeter Maydell 
19390aa8e700SRichard Henderson     read_neon_element64(rn_64, a->vn, 0, MO_64);
19400aa8e700SRichard Henderson     read_neon_element64(rm_64, a->vm, 0, MO_64);
19410fa1ab03SPeter Maydell 
19420fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
19430fa1ab03SPeter Maydell 
19440fa1ab03SPeter Maydell     narrowfn(rd0, rn_64);
19450fa1ab03SPeter Maydell 
19460aa8e700SRichard Henderson     read_neon_element64(rn_64, a->vn, 1, MO_64);
19470aa8e700SRichard Henderson     read_neon_element64(rm_64, a->vm, 1, MO_64);
19480fa1ab03SPeter Maydell 
19490fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
19500fa1ab03SPeter Maydell 
19510fa1ab03SPeter Maydell     narrowfn(rd1, rn_64);
19520fa1ab03SPeter Maydell 
1953a712266fSRichard Henderson     write_neon_element32(rd0, a->vd, 0, MO_32);
1954a712266fSRichard Henderson     write_neon_element32(rd1, a->vd, 1, MO_32);
19550fa1ab03SPeter Maydell 
1956a712266fSRichard Henderson     tcg_temp_free_i32(rd0);
1957a712266fSRichard Henderson     tcg_temp_free_i32(rd1);
19580fa1ab03SPeter Maydell     tcg_temp_free_i64(rn_64);
19590fa1ab03SPeter Maydell     tcg_temp_free_i64(rm_64);
19600fa1ab03SPeter Maydell 
19610fa1ab03SPeter Maydell     return true;
19620fa1ab03SPeter Maydell }
19630fa1ab03SPeter Maydell 
19640fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP)                       \
19650fa1ab03SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
19660fa1ab03SPeter Maydell     {                                                                   \
19670fa1ab03SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
19680fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u16,                                \
19690fa1ab03SPeter Maydell             gen_helper_neon_##OP##l_u32,                                \
19700fa1ab03SPeter Maydell             tcg_gen_##OP##_i64,                                         \
19710fa1ab03SPeter Maydell             NULL,                                                       \
19720fa1ab03SPeter Maydell         };                                                              \
19730fa1ab03SPeter Maydell         static NeonGenNarrowFn * const narrowfn[] = {                   \
19740fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u8,                     \
19750fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u16,                    \
19760fa1ab03SPeter Maydell             EXTOP,                                                      \
19770fa1ab03SPeter Maydell             NULL,                                                       \
19780fa1ab03SPeter Maydell         };                                                              \
19790fa1ab03SPeter Maydell         return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]);   \
19800fa1ab03SPeter Maydell     }
19810fa1ab03SPeter Maydell 
19820fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn)
19830fa1ab03SPeter Maydell {
19840fa1ab03SPeter Maydell     tcg_gen_addi_i64(rn, rn, 1u << 31);
19850fa1ab03SPeter Maydell     tcg_gen_extrh_i64_i32(rd, rn);
19860fa1ab03SPeter Maydell }
19870fa1ab03SPeter Maydell 
19880fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32)
19890fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32)
19900fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32)
19910fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32)
1992f5b28401SPeter Maydell 
1993f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a,
1994f5b28401SPeter Maydell                        NeonGenTwoOpWidenFn *opfn,
1995f5b28401SPeter Maydell                        NeonGenTwo64OpFn *accfn)
1996f5b28401SPeter Maydell {
1997f5b28401SPeter Maydell     /*
1998f5b28401SPeter Maydell      * 3-regs different lengths, long operations.
1999f5b28401SPeter Maydell      * These perform an operation on two inputs that returns a double-width
2000f5b28401SPeter Maydell      * result, and then possibly perform an accumulation operation of
2001f5b28401SPeter Maydell      * that result into the double-width destination.
2002f5b28401SPeter Maydell      */
2003f5b28401SPeter Maydell     TCGv_i64 rd0, rd1, tmp;
2004f5b28401SPeter Maydell     TCGv_i32 rn, rm;
2005f5b28401SPeter Maydell 
2006f5b28401SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2007f5b28401SPeter Maydell         return false;
2008f5b28401SPeter Maydell     }
2009f5b28401SPeter Maydell 
2010f5b28401SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2011f5b28401SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2012f5b28401SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2013f5b28401SPeter Maydell         return false;
2014f5b28401SPeter Maydell     }
2015f5b28401SPeter Maydell 
2016f5b28401SPeter Maydell     if (!opfn) {
2017f5b28401SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
2018f5b28401SPeter Maydell         return false;
2019f5b28401SPeter Maydell     }
2020f5b28401SPeter Maydell 
2021f5b28401SPeter Maydell     if (a->vd & 1) {
2022f5b28401SPeter Maydell         return false;
2023f5b28401SPeter Maydell     }
2024f5b28401SPeter Maydell 
2025f5b28401SPeter Maydell     if (!vfp_access_check(s)) {
2026f5b28401SPeter Maydell         return true;
2027f5b28401SPeter Maydell     }
2028f5b28401SPeter Maydell 
2029f5b28401SPeter Maydell     rd0 = tcg_temp_new_i64();
2030f5b28401SPeter Maydell     rd1 = tcg_temp_new_i64();
2031f5b28401SPeter Maydell 
2032a712266fSRichard Henderson     rn = tcg_temp_new_i32();
2033a712266fSRichard Henderson     rm = tcg_temp_new_i32();
2034a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 0, MO_32);
2035a712266fSRichard Henderson     read_neon_element32(rm, a->vm, 0, MO_32);
2036f5b28401SPeter Maydell     opfn(rd0, rn, rm);
2037f5b28401SPeter Maydell 
2038a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 1, MO_32);
2039a712266fSRichard Henderson     read_neon_element32(rm, a->vm, 1, MO_32);
2040f5b28401SPeter Maydell     opfn(rd1, rn, rm);
2041f5b28401SPeter Maydell     tcg_temp_free_i32(rn);
2042f5b28401SPeter Maydell     tcg_temp_free_i32(rm);
2043f5b28401SPeter Maydell 
2044f5b28401SPeter Maydell     /* Don't store results until after all loads: they might overlap */
2045f5b28401SPeter Maydell     if (accfn) {
2046f5b28401SPeter Maydell         tmp = tcg_temp_new_i64();
20470aa8e700SRichard Henderson         read_neon_element64(tmp, a->vd, 0, MO_64);
20489f1a5f93SRichard Henderson         accfn(rd0, tmp, rd0);
20490aa8e700SRichard Henderson         read_neon_element64(tmp, a->vd, 1, MO_64);
20509f1a5f93SRichard Henderson         accfn(rd1, tmp, rd1);
2051f5b28401SPeter Maydell         tcg_temp_free_i64(tmp);
2052f5b28401SPeter Maydell     }
2053f5b28401SPeter Maydell 
20549f1a5f93SRichard Henderson     write_neon_element64(rd0, a->vd, 0, MO_64);
20559f1a5f93SRichard Henderson     write_neon_element64(rd1, a->vd, 1, MO_64);
2056f5b28401SPeter Maydell     tcg_temp_free_i64(rd0);
2057f5b28401SPeter Maydell     tcg_temp_free_i64(rd1);
2058f5b28401SPeter Maydell 
2059f5b28401SPeter Maydell     return true;
2060f5b28401SPeter Maydell }
2061f5b28401SPeter Maydell 
2062f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a)
2063f5b28401SPeter Maydell {
2064f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2065f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2066f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2067f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2068f5b28401SPeter Maydell         NULL,
2069f5b28401SPeter Maydell     };
2070f5b28401SPeter Maydell 
2071f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2072f5b28401SPeter Maydell }
2073f5b28401SPeter Maydell 
2074f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a)
2075f5b28401SPeter Maydell {
2076f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2077f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2078f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2079f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2080f5b28401SPeter Maydell         NULL,
2081f5b28401SPeter Maydell     };
2082f5b28401SPeter Maydell 
2083f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
2084f5b28401SPeter Maydell }
2085f5b28401SPeter Maydell 
2086f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a)
2087f5b28401SPeter Maydell {
2088f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2089f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
2090f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
2091f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
2092f5b28401SPeter Maydell         NULL,
2093f5b28401SPeter Maydell     };
2094f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2095f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2096f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2097f5b28401SPeter Maydell         tcg_gen_add_i64,
2098f5b28401SPeter Maydell         NULL,
2099f5b28401SPeter Maydell     };
2100f5b28401SPeter Maydell 
2101f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2102f5b28401SPeter Maydell }
2103f5b28401SPeter Maydell 
2104f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
2105f5b28401SPeter Maydell {
2106f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
2107f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
2108f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
2109f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
2110f5b28401SPeter Maydell         NULL,
2111f5b28401SPeter Maydell     };
2112f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
2113f5b28401SPeter Maydell         gen_helper_neon_addl_u16,
2114f5b28401SPeter Maydell         gen_helper_neon_addl_u32,
2115f5b28401SPeter Maydell         tcg_gen_add_i64,
2116f5b28401SPeter Maydell         NULL,
2117f5b28401SPeter Maydell     };
2118f5b28401SPeter Maydell 
2119f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
2120f5b28401SPeter Maydell }
21213a1d9eb0SPeter Maydell 
21223a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
21233a1d9eb0SPeter Maydell {
21243a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
21253a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
21263a1d9eb0SPeter Maydell 
21273a1d9eb0SPeter Maydell     tcg_gen_muls2_i32(lo, hi, rn, rm);
21283a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
21293a1d9eb0SPeter Maydell 
21303a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
21313a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
21323a1d9eb0SPeter Maydell }
21333a1d9eb0SPeter Maydell 
21343a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
21353a1d9eb0SPeter Maydell {
21363a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
21373a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
21383a1d9eb0SPeter Maydell 
21393a1d9eb0SPeter Maydell     tcg_gen_mulu2_i32(lo, hi, rn, rm);
21403a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
21413a1d9eb0SPeter Maydell 
21423a1d9eb0SPeter Maydell     tcg_temp_free_i32(lo);
21433a1d9eb0SPeter Maydell     tcg_temp_free_i32(hi);
21443a1d9eb0SPeter Maydell }
21453a1d9eb0SPeter Maydell 
21463a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a)
21473a1d9eb0SPeter Maydell {
21483a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
21493a1d9eb0SPeter Maydell         gen_helper_neon_mull_s8,
21503a1d9eb0SPeter Maydell         gen_helper_neon_mull_s16,
21513a1d9eb0SPeter Maydell         gen_mull_s32,
21523a1d9eb0SPeter Maydell         NULL,
21533a1d9eb0SPeter Maydell     };
21543a1d9eb0SPeter Maydell 
21553a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
21563a1d9eb0SPeter Maydell }
21573a1d9eb0SPeter Maydell 
21583a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
21593a1d9eb0SPeter Maydell {
21603a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
21613a1d9eb0SPeter Maydell         gen_helper_neon_mull_u8,
21623a1d9eb0SPeter Maydell         gen_helper_neon_mull_u16,
21633a1d9eb0SPeter Maydell         gen_mull_u32,
21643a1d9eb0SPeter Maydell         NULL,
21653a1d9eb0SPeter Maydell     };
21663a1d9eb0SPeter Maydell 
21673a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
21683a1d9eb0SPeter Maydell }
21693a1d9eb0SPeter Maydell 
21703a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC)                                         \
21713a1d9eb0SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
21723a1d9eb0SPeter Maydell     {                                                                   \
21733a1d9eb0SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
21743a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##8,                                  \
21753a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
21763a1d9eb0SPeter Maydell             gen_##MULL##32,                                             \
21773a1d9eb0SPeter Maydell             NULL,                                                       \
21783a1d9eb0SPeter Maydell         };                                                              \
21793a1d9eb0SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
21803a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u16,                               \
21813a1d9eb0SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
21823a1d9eb0SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
21833a1d9eb0SPeter Maydell             NULL,                                                       \
21843a1d9eb0SPeter Maydell         };                                                              \
21853a1d9eb0SPeter Maydell         return do_long_3d(s, a, opfn[a->size], accfn[a->size]);         \
21863a1d9eb0SPeter Maydell     }
21873a1d9eb0SPeter Maydell 
21883a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add)
21893a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add)
21903a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub)
21913a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub)
21929546ca59SPeter Maydell 
21939546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
21949546ca59SPeter Maydell {
21959546ca59SPeter Maydell     gen_helper_neon_mull_s16(rd, rn, rm);
21969546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd);
21979546ca59SPeter Maydell }
21989546ca59SPeter Maydell 
21999546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
22009546ca59SPeter Maydell {
22019546ca59SPeter Maydell     gen_mull_s32(rd, rn, rm);
22029546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd);
22039546ca59SPeter Maydell }
22049546ca59SPeter Maydell 
22059546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a)
22069546ca59SPeter Maydell {
22079546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22089546ca59SPeter Maydell         NULL,
22099546ca59SPeter Maydell         gen_VQDMULL_16,
22109546ca59SPeter Maydell         gen_VQDMULL_32,
22119546ca59SPeter Maydell         NULL,
22129546ca59SPeter Maydell     };
22139546ca59SPeter Maydell 
22149546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
22159546ca59SPeter Maydell }
22169546ca59SPeter Maydell 
22179546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22189546ca59SPeter Maydell {
22199546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
22209546ca59SPeter Maydell }
22219546ca59SPeter Maydell 
22229546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22239546ca59SPeter Maydell {
22249546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
22259546ca59SPeter Maydell }
22269546ca59SPeter Maydell 
22279546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a)
22289546ca59SPeter Maydell {
22299546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22309546ca59SPeter Maydell         NULL,
22319546ca59SPeter Maydell         gen_VQDMULL_16,
22329546ca59SPeter Maydell         gen_VQDMULL_32,
22339546ca59SPeter Maydell         NULL,
22349546ca59SPeter Maydell     };
22359546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
22369546ca59SPeter Maydell         NULL,
22379546ca59SPeter Maydell         gen_VQDMLAL_acc_16,
22389546ca59SPeter Maydell         gen_VQDMLAL_acc_32,
22399546ca59SPeter Maydell         NULL,
22409546ca59SPeter Maydell     };
22419546ca59SPeter Maydell 
22429546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
22439546ca59SPeter Maydell }
22449546ca59SPeter Maydell 
22459546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22469546ca59SPeter Maydell {
22479546ca59SPeter Maydell     gen_helper_neon_negl_u32(rm, rm);
22489546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm);
22499546ca59SPeter Maydell }
22509546ca59SPeter Maydell 
22519546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
22529546ca59SPeter Maydell {
22539546ca59SPeter Maydell     tcg_gen_neg_i64(rm, rm);
22549546ca59SPeter Maydell     gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm);
22559546ca59SPeter Maydell }
22569546ca59SPeter Maydell 
22579546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a)
22589546ca59SPeter Maydell {
22599546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
22609546ca59SPeter Maydell         NULL,
22619546ca59SPeter Maydell         gen_VQDMULL_16,
22629546ca59SPeter Maydell         gen_VQDMULL_32,
22639546ca59SPeter Maydell         NULL,
22649546ca59SPeter Maydell     };
22659546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
22669546ca59SPeter Maydell         NULL,
22679546ca59SPeter Maydell         gen_VQDMLSL_acc_16,
22689546ca59SPeter Maydell         gen_VQDMLSL_acc_32,
22699546ca59SPeter Maydell         NULL,
22709546ca59SPeter Maydell     };
22719546ca59SPeter Maydell 
22729546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
22739546ca59SPeter Maydell }
227418fb58d5SPeter Maydell 
227518fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
227618fb58d5SPeter Maydell {
227718fb58d5SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
227818fb58d5SPeter Maydell 
227918fb58d5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
228018fb58d5SPeter Maydell         return false;
228118fb58d5SPeter Maydell     }
228218fb58d5SPeter Maydell 
228318fb58d5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
228418fb58d5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
228518fb58d5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
228618fb58d5SPeter Maydell         return false;
228718fb58d5SPeter Maydell     }
228818fb58d5SPeter Maydell 
228918fb58d5SPeter Maydell     if (a->vd & 1) {
229018fb58d5SPeter Maydell         return false;
229118fb58d5SPeter Maydell     }
229218fb58d5SPeter Maydell 
229318fb58d5SPeter Maydell     switch (a->size) {
229418fb58d5SPeter Maydell     case 0:
229518fb58d5SPeter Maydell         fn_gvec = gen_helper_neon_pmull_h;
229618fb58d5SPeter Maydell         break;
229718fb58d5SPeter Maydell     case 2:
229818fb58d5SPeter Maydell         if (!dc_isar_feature(aa32_pmull, s)) {
229918fb58d5SPeter Maydell             return false;
230018fb58d5SPeter Maydell         }
230118fb58d5SPeter Maydell         fn_gvec = gen_helper_gvec_pmull_q;
230218fb58d5SPeter Maydell         break;
230318fb58d5SPeter Maydell     default:
230418fb58d5SPeter Maydell         return false;
230518fb58d5SPeter Maydell     }
230618fb58d5SPeter Maydell 
230718fb58d5SPeter Maydell     if (!vfp_access_check(s)) {
230818fb58d5SPeter Maydell         return true;
230918fb58d5SPeter Maydell     }
231018fb58d5SPeter Maydell 
2311015ee81aSRichard Henderson     tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd),
2312015ee81aSRichard Henderson                        neon_full_reg_offset(a->vn),
2313015ee81aSRichard Henderson                        neon_full_reg_offset(a->vm),
231418fb58d5SPeter Maydell                        16, 16, 0, fn_gvec);
231518fb58d5SPeter Maydell     return true;
231618fb58d5SPeter Maydell }
231796fc80f5SPeter Maydell 
231896fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var)
231996fc80f5SPeter Maydell {
232096fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
232196fc80f5SPeter Maydell     tcg_gen_ext16u_i32(var, var);
232296fc80f5SPeter Maydell     tcg_gen_shli_i32(tmp, var, 16);
232396fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
232496fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
232596fc80f5SPeter Maydell }
232696fc80f5SPeter Maydell 
232796fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var)
232896fc80f5SPeter Maydell {
232996fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
233096fc80f5SPeter Maydell     tcg_gen_andi_i32(var, var, 0xffff0000);
233196fc80f5SPeter Maydell     tcg_gen_shri_i32(tmp, var, 16);
233296fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
233396fc80f5SPeter Maydell     tcg_temp_free_i32(tmp);
233496fc80f5SPeter Maydell }
233596fc80f5SPeter Maydell 
233696fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg)
233796fc80f5SPeter Maydell {
2338a712266fSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
2339a712266fSRichard Henderson     if (size == MO_16) {
2340a712266fSRichard Henderson         read_neon_element32(tmp, reg & 7, reg >> 4, MO_32);
234196fc80f5SPeter Maydell         if (reg & 8) {
234296fc80f5SPeter Maydell             gen_neon_dup_high16(tmp);
234396fc80f5SPeter Maydell         } else {
234496fc80f5SPeter Maydell             gen_neon_dup_low16(tmp);
234596fc80f5SPeter Maydell         }
234696fc80f5SPeter Maydell     } else {
2347a712266fSRichard Henderson         read_neon_element32(tmp, reg & 15, reg >> 4, MO_32);
234896fc80f5SPeter Maydell     }
234996fc80f5SPeter Maydell     return tmp;
235096fc80f5SPeter Maydell }
235196fc80f5SPeter Maydell 
235296fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a,
235396fc80f5SPeter Maydell                        NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn)
235496fc80f5SPeter Maydell {
235596fc80f5SPeter Maydell     /*
235696fc80f5SPeter Maydell      * Two registers and a scalar: perform an operation between
235796fc80f5SPeter Maydell      * the input elements and the scalar, and then possibly
235896fc80f5SPeter Maydell      * perform an accumulation operation of that result into the
235996fc80f5SPeter Maydell      * destination.
236096fc80f5SPeter Maydell      */
2361a712266fSRichard Henderson     TCGv_i32 scalar, tmp;
236296fc80f5SPeter Maydell     int pass;
236396fc80f5SPeter Maydell 
236496fc80f5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
236596fc80f5SPeter Maydell         return false;
236696fc80f5SPeter Maydell     }
236796fc80f5SPeter Maydell 
236896fc80f5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
236996fc80f5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
237096fc80f5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
237196fc80f5SPeter Maydell         return false;
237296fc80f5SPeter Maydell     }
237396fc80f5SPeter Maydell 
237496fc80f5SPeter Maydell     if (!opfn) {
237596fc80f5SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
237696fc80f5SPeter Maydell         return false;
237796fc80f5SPeter Maydell     }
237896fc80f5SPeter Maydell 
237996fc80f5SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
238096fc80f5SPeter Maydell         return false;
238196fc80f5SPeter Maydell     }
238296fc80f5SPeter Maydell 
238396fc80f5SPeter Maydell     if (!vfp_access_check(s)) {
238496fc80f5SPeter Maydell         return true;
238596fc80f5SPeter Maydell     }
238696fc80f5SPeter Maydell 
238796fc80f5SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2388a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
238996fc80f5SPeter Maydell 
239096fc80f5SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2391a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, pass, MO_32);
239296fc80f5SPeter Maydell         opfn(tmp, tmp, scalar);
239396fc80f5SPeter Maydell         if (accfn) {
2394a712266fSRichard Henderson             TCGv_i32 rd = tcg_temp_new_i32();
2395a712266fSRichard Henderson             read_neon_element32(rd, a->vd, pass, MO_32);
239696fc80f5SPeter Maydell             accfn(tmp, rd, tmp);
239796fc80f5SPeter Maydell             tcg_temp_free_i32(rd);
239896fc80f5SPeter Maydell         }
2399a712266fSRichard Henderson         write_neon_element32(tmp, a->vd, pass, MO_32);
240096fc80f5SPeter Maydell     }
2401a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
240296fc80f5SPeter Maydell     tcg_temp_free_i32(scalar);
240396fc80f5SPeter Maydell     return true;
240496fc80f5SPeter Maydell }
240596fc80f5SPeter Maydell 
240696fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a)
240796fc80f5SPeter Maydell {
240896fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
240996fc80f5SPeter Maydell         NULL,
241096fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
241196fc80f5SPeter Maydell         tcg_gen_mul_i32,
241296fc80f5SPeter Maydell         NULL,
241396fc80f5SPeter Maydell     };
241496fc80f5SPeter Maydell 
241596fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
241696fc80f5SPeter Maydell }
241796fc80f5SPeter Maydell 
241896fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a)
241996fc80f5SPeter Maydell {
242096fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
242196fc80f5SPeter Maydell         NULL,
242296fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
242396fc80f5SPeter Maydell         tcg_gen_mul_i32,
242496fc80f5SPeter Maydell         NULL,
242596fc80f5SPeter Maydell     };
242696fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
242796fc80f5SPeter Maydell         NULL,
242896fc80f5SPeter Maydell         gen_helper_neon_add_u16,
242996fc80f5SPeter Maydell         tcg_gen_add_i32,
243096fc80f5SPeter Maydell         NULL,
243196fc80f5SPeter Maydell     };
243296fc80f5SPeter Maydell 
243396fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
243496fc80f5SPeter Maydell }
243596fc80f5SPeter Maydell 
243696fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a)
243796fc80f5SPeter Maydell {
243896fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
243996fc80f5SPeter Maydell         NULL,
244096fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
244196fc80f5SPeter Maydell         tcg_gen_mul_i32,
244296fc80f5SPeter Maydell         NULL,
244396fc80f5SPeter Maydell     };
244496fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
244596fc80f5SPeter Maydell         NULL,
244696fc80f5SPeter Maydell         gen_helper_neon_sub_u16,
244796fc80f5SPeter Maydell         tcg_gen_sub_i32,
244896fc80f5SPeter Maydell         NULL,
244996fc80f5SPeter Maydell     };
245096fc80f5SPeter Maydell 
245196fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
245296fc80f5SPeter Maydell }
245385ac9aefSPeter Maydell 
2454fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a,
2455fc8ae790SPeter Maydell                               gen_helper_gvec_3_ptr *fn)
2456fc8ae790SPeter Maydell {
2457fc8ae790SPeter Maydell     /* Two registers and a scalar, using gvec */
2458fc8ae790SPeter Maydell     int vec_size = a->q ? 16 : 8;
2459015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
2460015ee81aSRichard Henderson     int rn_ofs = neon_full_reg_offset(a->vn);
2461fc8ae790SPeter Maydell     int rm_ofs;
2462fc8ae790SPeter Maydell     int idx;
2463fc8ae790SPeter Maydell     TCGv_ptr fpstatus;
2464fc8ae790SPeter Maydell 
2465fc8ae790SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2466fc8ae790SPeter Maydell         return false;
2467fc8ae790SPeter Maydell     }
2468fc8ae790SPeter Maydell 
2469fc8ae790SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2470fc8ae790SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2471fc8ae790SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2472fc8ae790SPeter Maydell         return false;
2473fc8ae790SPeter Maydell     }
2474fc8ae790SPeter Maydell 
2475fc8ae790SPeter Maydell     if (!fn) {
2476fc8ae790SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2477fc8ae790SPeter Maydell         return false;
2478fc8ae790SPeter Maydell     }
2479fc8ae790SPeter Maydell 
2480fc8ae790SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2481fc8ae790SPeter Maydell         return false;
2482fc8ae790SPeter Maydell     }
2483fc8ae790SPeter Maydell 
2484fc8ae790SPeter Maydell     if (!vfp_access_check(s)) {
2485fc8ae790SPeter Maydell         return true;
2486fc8ae790SPeter Maydell     }
2487fc8ae790SPeter Maydell 
2488fc8ae790SPeter Maydell     /* a->vm is M:Vm, which encodes both register and index */
2489fc8ae790SPeter Maydell     idx = extract32(a->vm, a->size + 2, 2);
2490fc8ae790SPeter Maydell     a->vm = extract32(a->vm, 0, a->size + 2);
2491015ee81aSRichard Henderson     rm_ofs = neon_full_reg_offset(a->vm);
2492fc8ae790SPeter Maydell 
2493fc8ae790SPeter Maydell     fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD);
2494fc8ae790SPeter Maydell     tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus,
2495fc8ae790SPeter Maydell                        vec_size, vec_size, idx, fn);
2496fc8ae790SPeter Maydell     tcg_temp_free_ptr(fpstatus);
2497fc8ae790SPeter Maydell     return true;
2498fc8ae790SPeter Maydell }
2499fc8ae790SPeter Maydell 
2500fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC)                                       \
2501fc8ae790SPeter Maydell     static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a)   \
250285ac9aefSPeter Maydell     {                                                                   \
2503fc8ae790SPeter Maydell         static gen_helper_gvec_3_ptr * const opfn[] = {                 \
2504fc8ae790SPeter Maydell             NULL,                                                       \
2505fc8ae790SPeter Maydell             gen_helper_##FUNC##_h,                                      \
2506fc8ae790SPeter Maydell             gen_helper_##FUNC##_s,                                      \
2507fc8ae790SPeter Maydell             NULL,                                                       \
2508fc8ae790SPeter Maydell         };                                                              \
2509fc8ae790SPeter Maydell         if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \
2510fc8ae790SPeter Maydell             return false;                                               \
2511fc8ae790SPeter Maydell         }                                                               \
2512fc8ae790SPeter Maydell         return do_2scalar_fp_vec(s, a, opfn[a->size]);                  \
251385ac9aefSPeter Maydell     }
251485ac9aefSPeter Maydell 
2515fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx)
2516fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx)
2517fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx)
2518b2fc7be9SPeter Maydell 
2519b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
2520b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
2521b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16)
2522b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32)
2523b2fc7be9SPeter Maydell 
2524b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a)
2525b2fc7be9SPeter Maydell {
2526b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2527b2fc7be9SPeter Maydell         NULL,
2528b2fc7be9SPeter Maydell         gen_VQDMULH_16,
2529b2fc7be9SPeter Maydell         gen_VQDMULH_32,
2530b2fc7be9SPeter Maydell         NULL,
2531b2fc7be9SPeter Maydell     };
2532b2fc7be9SPeter Maydell 
2533b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2534b2fc7be9SPeter Maydell }
2535b2fc7be9SPeter Maydell 
2536b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a)
2537b2fc7be9SPeter Maydell {
2538b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2539b2fc7be9SPeter Maydell         NULL,
2540b2fc7be9SPeter Maydell         gen_VQRDMULH_16,
2541b2fc7be9SPeter Maydell         gen_VQRDMULH_32,
2542b2fc7be9SPeter Maydell         NULL,
2543b2fc7be9SPeter Maydell     };
2544b2fc7be9SPeter Maydell 
2545b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2546b2fc7be9SPeter Maydell }
2547aa318f5bSPeter Maydell 
2548aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a,
2549aa318f5bSPeter Maydell                             NeonGenThreeOpEnvFn *opfn)
2550aa318f5bSPeter Maydell {
2551aa318f5bSPeter Maydell     /*
2552aa318f5bSPeter Maydell      * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn
2553aa318f5bSPeter Maydell      * performs a kind of fused op-then-accumulate using a helper
2554aa318f5bSPeter Maydell      * function that takes all of rd, rn and the scalar at once.
2555aa318f5bSPeter Maydell      */
2556a712266fSRichard Henderson     TCGv_i32 scalar, rn, rd;
2557aa318f5bSPeter Maydell     int pass;
2558aa318f5bSPeter Maydell 
2559aa318f5bSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2560aa318f5bSPeter Maydell         return false;
2561aa318f5bSPeter Maydell     }
2562aa318f5bSPeter Maydell 
2563aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_rdm, s)) {
2564aa318f5bSPeter Maydell         return false;
2565aa318f5bSPeter Maydell     }
2566aa318f5bSPeter Maydell 
2567aa318f5bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2568aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2569aa318f5bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2570aa318f5bSPeter Maydell         return false;
2571aa318f5bSPeter Maydell     }
2572aa318f5bSPeter Maydell 
2573aa318f5bSPeter Maydell     if (!opfn) {
2574aa318f5bSPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2575aa318f5bSPeter Maydell         return false;
2576aa318f5bSPeter Maydell     }
2577aa318f5bSPeter Maydell 
2578aa318f5bSPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2579aa318f5bSPeter Maydell         return false;
2580aa318f5bSPeter Maydell     }
2581aa318f5bSPeter Maydell 
2582aa318f5bSPeter Maydell     if (!vfp_access_check(s)) {
2583aa318f5bSPeter Maydell         return true;
2584aa318f5bSPeter Maydell     }
2585aa318f5bSPeter Maydell 
2586aa318f5bSPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2587a712266fSRichard Henderson     rn = tcg_temp_new_i32();
2588a712266fSRichard Henderson     rd = tcg_temp_new_i32();
2589aa318f5bSPeter Maydell 
2590aa318f5bSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2591a712266fSRichard Henderson         read_neon_element32(rn, a->vn, pass, MO_32);
2592a712266fSRichard Henderson         read_neon_element32(rd, a->vd, pass, MO_32);
2593aa318f5bSPeter Maydell         opfn(rd, cpu_env, rn, scalar, rd);
2594a712266fSRichard Henderson         write_neon_element32(rd, a->vd, pass, MO_32);
2595aa318f5bSPeter Maydell     }
2596a712266fSRichard Henderson     tcg_temp_free_i32(rn);
2597a712266fSRichard Henderson     tcg_temp_free_i32(rd);
2598aa318f5bSPeter Maydell     tcg_temp_free_i32(scalar);
2599aa318f5bSPeter Maydell 
2600aa318f5bSPeter Maydell     return true;
2601aa318f5bSPeter Maydell }
2602aa318f5bSPeter Maydell 
2603aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a)
2604aa318f5bSPeter Maydell {
2605aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2606aa318f5bSPeter Maydell         NULL,
2607aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s16,
2608aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s32,
2609aa318f5bSPeter Maydell         NULL,
2610aa318f5bSPeter Maydell     };
2611aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2612aa318f5bSPeter Maydell }
2613aa318f5bSPeter Maydell 
2614aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a)
2615aa318f5bSPeter Maydell {
2616aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2617aa318f5bSPeter Maydell         NULL,
2618aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s16,
2619aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s32,
2620aa318f5bSPeter Maydell         NULL,
2621aa318f5bSPeter Maydell     };
2622aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2623aa318f5bSPeter Maydell }
262477e576a9SPeter Maydell 
262577e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a,
262677e576a9SPeter Maydell                             NeonGenTwoOpWidenFn *opfn,
262777e576a9SPeter Maydell                             NeonGenTwo64OpFn *accfn)
262877e576a9SPeter Maydell {
262977e576a9SPeter Maydell     /*
263077e576a9SPeter Maydell      * Two registers and a scalar, long operations: perform an
263177e576a9SPeter Maydell      * operation on the input elements and the scalar which produces
263277e576a9SPeter Maydell      * a double-width result, and then possibly perform an accumulation
263377e576a9SPeter Maydell      * operation of that result into the destination.
263477e576a9SPeter Maydell      */
263577e576a9SPeter Maydell     TCGv_i32 scalar, rn;
263677e576a9SPeter Maydell     TCGv_i64 rn0_64, rn1_64;
263777e576a9SPeter Maydell 
263877e576a9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
263977e576a9SPeter Maydell         return false;
264077e576a9SPeter Maydell     }
264177e576a9SPeter Maydell 
264277e576a9SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
264377e576a9SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
264477e576a9SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
264577e576a9SPeter Maydell         return false;
264677e576a9SPeter Maydell     }
264777e576a9SPeter Maydell 
264877e576a9SPeter Maydell     if (!opfn) {
264977e576a9SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
265077e576a9SPeter Maydell         return false;
265177e576a9SPeter Maydell     }
265277e576a9SPeter Maydell 
265377e576a9SPeter Maydell     if (a->vd & 1) {
265477e576a9SPeter Maydell         return false;
265577e576a9SPeter Maydell     }
265677e576a9SPeter Maydell 
265777e576a9SPeter Maydell     if (!vfp_access_check(s)) {
265877e576a9SPeter Maydell         return true;
265977e576a9SPeter Maydell     }
266077e576a9SPeter Maydell 
266177e576a9SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
266277e576a9SPeter Maydell 
266377e576a9SPeter Maydell     /* Load all inputs before writing any outputs, in case of overlap */
2664a712266fSRichard Henderson     rn = tcg_temp_new_i32();
2665a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 0, MO_32);
266677e576a9SPeter Maydell     rn0_64 = tcg_temp_new_i64();
266777e576a9SPeter Maydell     opfn(rn0_64, rn, scalar);
266877e576a9SPeter Maydell 
2669a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 1, MO_32);
267077e576a9SPeter Maydell     rn1_64 = tcg_temp_new_i64();
267177e576a9SPeter Maydell     opfn(rn1_64, rn, scalar);
267277e576a9SPeter Maydell     tcg_temp_free_i32(rn);
267377e576a9SPeter Maydell     tcg_temp_free_i32(scalar);
267477e576a9SPeter Maydell 
267577e576a9SPeter Maydell     if (accfn) {
267677e576a9SPeter Maydell         TCGv_i64 t64 = tcg_temp_new_i64();
26770aa8e700SRichard Henderson         read_neon_element64(t64, a->vd, 0, MO_64);
26789f1a5f93SRichard Henderson         accfn(rn0_64, t64, rn0_64);
26790aa8e700SRichard Henderson         read_neon_element64(t64, a->vd, 1, MO_64);
26809f1a5f93SRichard Henderson         accfn(rn1_64, t64, rn1_64);
268177e576a9SPeter Maydell         tcg_temp_free_i64(t64);
26829f1a5f93SRichard Henderson     }
26839f1a5f93SRichard Henderson 
26840aa8e700SRichard Henderson     write_neon_element64(rn0_64, a->vd, 0, MO_64);
26850aa8e700SRichard Henderson     write_neon_element64(rn1_64, a->vd, 1, MO_64);
268677e576a9SPeter Maydell     tcg_temp_free_i64(rn0_64);
268777e576a9SPeter Maydell     tcg_temp_free_i64(rn1_64);
268877e576a9SPeter Maydell     return true;
268977e576a9SPeter Maydell }
269077e576a9SPeter Maydell 
269177e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a)
269277e576a9SPeter Maydell {
269377e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
269477e576a9SPeter Maydell         NULL,
269577e576a9SPeter Maydell         gen_helper_neon_mull_s16,
269677e576a9SPeter Maydell         gen_mull_s32,
269777e576a9SPeter Maydell         NULL,
269877e576a9SPeter Maydell     };
269977e576a9SPeter Maydell 
270077e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
270177e576a9SPeter Maydell }
270277e576a9SPeter Maydell 
270377e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a)
270477e576a9SPeter Maydell {
270577e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
270677e576a9SPeter Maydell         NULL,
270777e576a9SPeter Maydell         gen_helper_neon_mull_u16,
270877e576a9SPeter Maydell         gen_mull_u32,
270977e576a9SPeter Maydell         NULL,
271077e576a9SPeter Maydell     };
271177e576a9SPeter Maydell 
271277e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
271377e576a9SPeter Maydell }
271477e576a9SPeter Maydell 
271577e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC)                                   \
271677e576a9SPeter Maydell     static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a)     \
271777e576a9SPeter Maydell     {                                                                   \
271877e576a9SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
271977e576a9SPeter Maydell             NULL,                                                       \
272077e576a9SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
272177e576a9SPeter Maydell             gen_##MULL##32,                                             \
272277e576a9SPeter Maydell             NULL,                                                       \
272377e576a9SPeter Maydell         };                                                              \
272477e576a9SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
272577e576a9SPeter Maydell             NULL,                                                       \
272677e576a9SPeter Maydell             gen_helper_neon_##ACC##l_u32,                               \
272777e576a9SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
272877e576a9SPeter Maydell             NULL,                                                       \
272977e576a9SPeter Maydell         };                                                              \
273077e576a9SPeter Maydell         return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);    \
273177e576a9SPeter Maydell     }
273277e576a9SPeter Maydell 
273377e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add)
273477e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add)
273577e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub)
273677e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub)
273777e576a9SPeter Maydell 
273877e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a)
273977e576a9SPeter Maydell {
274077e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
274177e576a9SPeter Maydell         NULL,
274277e576a9SPeter Maydell         gen_VQDMULL_16,
274377e576a9SPeter Maydell         gen_VQDMULL_32,
274477e576a9SPeter Maydell         NULL,
274577e576a9SPeter Maydell     };
274677e576a9SPeter Maydell 
274777e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
274877e576a9SPeter Maydell }
274977e576a9SPeter Maydell 
275077e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a)
275177e576a9SPeter Maydell {
275277e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
275377e576a9SPeter Maydell         NULL,
275477e576a9SPeter Maydell         gen_VQDMULL_16,
275577e576a9SPeter Maydell         gen_VQDMULL_32,
275677e576a9SPeter Maydell         NULL,
275777e576a9SPeter Maydell     };
275877e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
275977e576a9SPeter Maydell         NULL,
276077e576a9SPeter Maydell         gen_VQDMLAL_acc_16,
276177e576a9SPeter Maydell         gen_VQDMLAL_acc_32,
276277e576a9SPeter Maydell         NULL,
276377e576a9SPeter Maydell     };
276477e576a9SPeter Maydell 
276577e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
276677e576a9SPeter Maydell }
276777e576a9SPeter Maydell 
276877e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a)
276977e576a9SPeter Maydell {
277077e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
277177e576a9SPeter Maydell         NULL,
277277e576a9SPeter Maydell         gen_VQDMULL_16,
277377e576a9SPeter Maydell         gen_VQDMULL_32,
277477e576a9SPeter Maydell         NULL,
277577e576a9SPeter Maydell     };
277677e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
277777e576a9SPeter Maydell         NULL,
277877e576a9SPeter Maydell         gen_VQDMLSL_acc_16,
277977e576a9SPeter Maydell         gen_VQDMLSL_acc_32,
278077e576a9SPeter Maydell         NULL,
278177e576a9SPeter Maydell     };
278277e576a9SPeter Maydell 
278377e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
278477e576a9SPeter Maydell }
27850aad761fSPeter Maydell 
27860aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
27870aad761fSPeter Maydell {
27880aad761fSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
27890aad761fSPeter Maydell         return false;
27900aad761fSPeter Maydell     }
27910aad761fSPeter Maydell 
27920aad761fSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
27930aad761fSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
27940aad761fSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
27950aad761fSPeter Maydell         return false;
27960aad761fSPeter Maydell     }
27970aad761fSPeter Maydell 
27980aad761fSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
27990aad761fSPeter Maydell         return false;
28000aad761fSPeter Maydell     }
28010aad761fSPeter Maydell 
28020aad761fSPeter Maydell     if (a->imm > 7 && !a->q) {
28030aad761fSPeter Maydell         return false;
28040aad761fSPeter Maydell     }
28050aad761fSPeter Maydell 
28060aad761fSPeter Maydell     if (!vfp_access_check(s)) {
28070aad761fSPeter Maydell         return true;
28080aad761fSPeter Maydell     }
28090aad761fSPeter Maydell 
28100aad761fSPeter Maydell     if (!a->q) {
28110aad761fSPeter Maydell         /* Extract 64 bits from <Vm:Vn> */
28120aad761fSPeter Maydell         TCGv_i64 left, right, dest;
28130aad761fSPeter Maydell 
28140aad761fSPeter Maydell         left = tcg_temp_new_i64();
28150aad761fSPeter Maydell         right = tcg_temp_new_i64();
28160aad761fSPeter Maydell         dest = tcg_temp_new_i64();
28170aad761fSPeter Maydell 
28180aa8e700SRichard Henderson         read_neon_element64(right, a->vn, 0, MO_64);
28190aa8e700SRichard Henderson         read_neon_element64(left, a->vm, 0, MO_64);
28200aad761fSPeter Maydell         tcg_gen_extract2_i64(dest, right, left, a->imm * 8);
28210aa8e700SRichard Henderson         write_neon_element64(dest, a->vd, 0, MO_64);
28220aad761fSPeter Maydell 
28230aad761fSPeter Maydell         tcg_temp_free_i64(left);
28240aad761fSPeter Maydell         tcg_temp_free_i64(right);
28250aad761fSPeter Maydell         tcg_temp_free_i64(dest);
28260aad761fSPeter Maydell     } else {
28270aad761fSPeter Maydell         /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */
28280aad761fSPeter Maydell         TCGv_i64 left, middle, right, destleft, destright;
28290aad761fSPeter Maydell 
28300aad761fSPeter Maydell         left = tcg_temp_new_i64();
28310aad761fSPeter Maydell         middle = tcg_temp_new_i64();
28320aad761fSPeter Maydell         right = tcg_temp_new_i64();
28330aad761fSPeter Maydell         destleft = tcg_temp_new_i64();
28340aad761fSPeter Maydell         destright = tcg_temp_new_i64();
28350aad761fSPeter Maydell 
28360aad761fSPeter Maydell         if (a->imm < 8) {
28370aa8e700SRichard Henderson             read_neon_element64(right, a->vn, 0, MO_64);
28380aa8e700SRichard Henderson             read_neon_element64(middle, a->vn, 1, MO_64);
28390aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, a->imm * 8);
28400aa8e700SRichard Henderson             read_neon_element64(left, a->vm, 0, MO_64);
28410aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8);
28420aad761fSPeter Maydell         } else {
28430aa8e700SRichard Henderson             read_neon_element64(right, a->vn, 1, MO_64);
28440aa8e700SRichard Henderson             read_neon_element64(middle, a->vm, 0, MO_64);
28450aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8);
28460aa8e700SRichard Henderson             read_neon_element64(left, a->vm, 1, MO_64);
28470aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8);
28480aad761fSPeter Maydell         }
28490aad761fSPeter Maydell 
28500aa8e700SRichard Henderson         write_neon_element64(destright, a->vd, 0, MO_64);
28510aa8e700SRichard Henderson         write_neon_element64(destleft, a->vd, 1, MO_64);
28520aad761fSPeter Maydell 
28530aad761fSPeter Maydell         tcg_temp_free_i64(destright);
28540aad761fSPeter Maydell         tcg_temp_free_i64(destleft);
28550aad761fSPeter Maydell         tcg_temp_free_i64(right);
28560aad761fSPeter Maydell         tcg_temp_free_i64(middle);
28570aad761fSPeter Maydell         tcg_temp_free_i64(left);
28580aad761fSPeter Maydell     }
28590aad761fSPeter Maydell     return true;
28600aad761fSPeter Maydell }
286154e96c74SPeter Maydell 
286254e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
286354e96c74SPeter Maydell {
2864604cef3eSRichard Henderson     TCGv_i64 val, def;
2865604cef3eSRichard Henderson     TCGv_i32 desc;
286654e96c74SPeter Maydell 
286754e96c74SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
286854e96c74SPeter Maydell         return false;
286954e96c74SPeter Maydell     }
287054e96c74SPeter Maydell 
287154e96c74SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
287254e96c74SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
287354e96c74SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
287454e96c74SPeter Maydell         return false;
287554e96c74SPeter Maydell     }
287654e96c74SPeter Maydell 
2877604cef3eSRichard Henderson     if ((a->vn + a->len + 1) > 32) {
287854e96c74SPeter Maydell         /*
287954e96c74SPeter Maydell          * This is UNPREDICTABLE; we choose to UNDEF to avoid the
288054e96c74SPeter Maydell          * helper function running off the end of the register file.
288154e96c74SPeter Maydell          */
288254e96c74SPeter Maydell         return false;
288354e96c74SPeter Maydell     }
2884a712266fSRichard Henderson 
2885b6c56c8aSPeter Maydell     if (!vfp_access_check(s)) {
2886b6c56c8aSPeter Maydell         return true;
2887b6c56c8aSPeter Maydell     }
2888b6c56c8aSPeter Maydell 
2889604cef3eSRichard Henderson     desc = tcg_const_i32((a->vn << 2) | a->len);
2890604cef3eSRichard Henderson     def = tcg_temp_new_i64();
289154e96c74SPeter Maydell     if (a->op) {
2892604cef3eSRichard Henderson         read_neon_element64(def, a->vd, 0, MO_64);
289354e96c74SPeter Maydell     } else {
2894604cef3eSRichard Henderson         tcg_gen_movi_i64(def, 0);
289554e96c74SPeter Maydell     }
2896604cef3eSRichard Henderson     val = tcg_temp_new_i64();
2897604cef3eSRichard Henderson     read_neon_element64(val, a->vm, 0, MO_64);
2898a712266fSRichard Henderson 
2899604cef3eSRichard Henderson     gen_helper_neon_tbl(val, cpu_env, desc, val, def);
2900604cef3eSRichard Henderson     write_neon_element64(val, a->vd, 0, MO_64);
2901604cef3eSRichard Henderson 
2902604cef3eSRichard Henderson     tcg_temp_free_i64(def);
2903604cef3eSRichard Henderson     tcg_temp_free_i64(val);
2904604cef3eSRichard Henderson     tcg_temp_free_i32(desc);
290554e96c74SPeter Maydell     return true;
290654e96c74SPeter Maydell }
29079aaa23c2SPeter Maydell 
29089aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
29099aaa23c2SPeter Maydell {
29109aaa23c2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
29119aaa23c2SPeter Maydell         return false;
29129aaa23c2SPeter Maydell     }
29139aaa23c2SPeter Maydell 
29149aaa23c2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
29159aaa23c2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
29169aaa23c2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
29179aaa23c2SPeter Maydell         return false;
29189aaa23c2SPeter Maydell     }
29199aaa23c2SPeter Maydell 
29209aaa23c2SPeter Maydell     if (a->vd & a->q) {
29219aaa23c2SPeter Maydell         return false;
29229aaa23c2SPeter Maydell     }
29239aaa23c2SPeter Maydell 
29249aaa23c2SPeter Maydell     if (!vfp_access_check(s)) {
29259aaa23c2SPeter Maydell         return true;
29269aaa23c2SPeter Maydell     }
29279aaa23c2SPeter Maydell 
2928015ee81aSRichard Henderson     tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd),
29299aaa23c2SPeter Maydell                          neon_element_offset(a->vm, a->index, a->size),
29309aaa23c2SPeter Maydell                          a->q ? 16 : 8, a->q ? 16 : 8);
29319aaa23c2SPeter Maydell     return true;
29329aaa23c2SPeter Maydell }
2933353d2b85SPeter Maydell 
2934353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
2935353d2b85SPeter Maydell {
2936353d2b85SPeter Maydell     int pass, half;
2937a712266fSRichard Henderson     TCGv_i32 tmp[2];
2938353d2b85SPeter Maydell 
2939353d2b85SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2940353d2b85SPeter Maydell         return false;
2941353d2b85SPeter Maydell     }
2942353d2b85SPeter Maydell 
2943353d2b85SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2944353d2b85SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2945353d2b85SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2946353d2b85SPeter Maydell         return false;
2947353d2b85SPeter Maydell     }
2948353d2b85SPeter Maydell 
2949353d2b85SPeter Maydell     if ((a->vd | a->vm) & a->q) {
2950353d2b85SPeter Maydell         return false;
2951353d2b85SPeter Maydell     }
2952353d2b85SPeter Maydell 
2953353d2b85SPeter Maydell     if (a->size == 3) {
2954353d2b85SPeter Maydell         return false;
2955353d2b85SPeter Maydell     }
2956353d2b85SPeter Maydell 
2957353d2b85SPeter Maydell     if (!vfp_access_check(s)) {
2958353d2b85SPeter Maydell         return true;
2959353d2b85SPeter Maydell     }
2960353d2b85SPeter Maydell 
2961a712266fSRichard Henderson     tmp[0] = tcg_temp_new_i32();
2962a712266fSRichard Henderson     tmp[1] = tcg_temp_new_i32();
2963353d2b85SPeter Maydell 
2964a712266fSRichard Henderson     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
2965353d2b85SPeter Maydell         for (half = 0; half < 2; half++) {
2966a712266fSRichard Henderson             read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32);
2967353d2b85SPeter Maydell             switch (a->size) {
2968353d2b85SPeter Maydell             case 0:
2969353d2b85SPeter Maydell                 tcg_gen_bswap32_i32(tmp[half], tmp[half]);
2970353d2b85SPeter Maydell                 break;
2971353d2b85SPeter Maydell             case 1:
29728ec3de70SPeter Maydell                 gen_swap_half(tmp[half], tmp[half]);
2973353d2b85SPeter Maydell                 break;
2974353d2b85SPeter Maydell             case 2:
2975353d2b85SPeter Maydell                 break;
2976353d2b85SPeter Maydell             default:
2977353d2b85SPeter Maydell                 g_assert_not_reached();
2978353d2b85SPeter Maydell             }
2979353d2b85SPeter Maydell         }
2980a712266fSRichard Henderson         write_neon_element32(tmp[1], a->vd, pass * 2, MO_32);
2981a712266fSRichard Henderson         write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32);
2982353d2b85SPeter Maydell     }
2983a712266fSRichard Henderson 
2984a712266fSRichard Henderson     tcg_temp_free_i32(tmp[0]);
2985a712266fSRichard Henderson     tcg_temp_free_i32(tmp[1]);
2986353d2b85SPeter Maydell     return true;
2987353d2b85SPeter Maydell }
29886106af3aSPeter Maydell 
29896106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a,
29906106af3aSPeter Maydell                               NeonGenWidenFn *widenfn,
29916106af3aSPeter Maydell                               NeonGenTwo64OpFn *opfn,
29926106af3aSPeter Maydell                               NeonGenTwo64OpFn *accfn)
29936106af3aSPeter Maydell {
29946106af3aSPeter Maydell     /*
29956106af3aSPeter Maydell      * Pairwise long operations: widen both halves of the pair,
29966106af3aSPeter Maydell      * combine the pairs with the opfn, and then possibly accumulate
29976106af3aSPeter Maydell      * into the destination with the accfn.
29986106af3aSPeter Maydell      */
29996106af3aSPeter Maydell     int pass;
30006106af3aSPeter Maydell 
30016106af3aSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
30026106af3aSPeter Maydell         return false;
30036106af3aSPeter Maydell     }
30046106af3aSPeter Maydell 
30056106af3aSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
30066106af3aSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
30076106af3aSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
30086106af3aSPeter Maydell         return false;
30096106af3aSPeter Maydell     }
30106106af3aSPeter Maydell 
30116106af3aSPeter Maydell     if ((a->vd | a->vm) & a->q) {
30126106af3aSPeter Maydell         return false;
30136106af3aSPeter Maydell     }
30146106af3aSPeter Maydell 
30156106af3aSPeter Maydell     if (!widenfn) {
30166106af3aSPeter Maydell         return false;
30176106af3aSPeter Maydell     }
30186106af3aSPeter Maydell 
30196106af3aSPeter Maydell     if (!vfp_access_check(s)) {
30206106af3aSPeter Maydell         return true;
30216106af3aSPeter Maydell     }
30226106af3aSPeter Maydell 
30236106af3aSPeter Maydell     for (pass = 0; pass < a->q + 1; pass++) {
30246106af3aSPeter Maydell         TCGv_i32 tmp;
30256106af3aSPeter Maydell         TCGv_i64 rm0_64, rm1_64, rd_64;
30266106af3aSPeter Maydell 
30276106af3aSPeter Maydell         rm0_64 = tcg_temp_new_i64();
30286106af3aSPeter Maydell         rm1_64 = tcg_temp_new_i64();
30296106af3aSPeter Maydell         rd_64 = tcg_temp_new_i64();
3030a712266fSRichard Henderson 
3031a712266fSRichard Henderson         tmp = tcg_temp_new_i32();
3032a712266fSRichard Henderson         read_neon_element32(tmp, a->vm, pass * 2, MO_32);
30336106af3aSPeter Maydell         widenfn(rm0_64, tmp);
3034a712266fSRichard Henderson         read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32);
30356106af3aSPeter Maydell         widenfn(rm1_64, tmp);
30366106af3aSPeter Maydell         tcg_temp_free_i32(tmp);
3037a712266fSRichard Henderson 
30386106af3aSPeter Maydell         opfn(rd_64, rm0_64, rm1_64);
30396106af3aSPeter Maydell         tcg_temp_free_i64(rm0_64);
30406106af3aSPeter Maydell         tcg_temp_free_i64(rm1_64);
30416106af3aSPeter Maydell 
30426106af3aSPeter Maydell         if (accfn) {
30436106af3aSPeter Maydell             TCGv_i64 tmp64 = tcg_temp_new_i64();
30440aa8e700SRichard Henderson             read_neon_element64(tmp64, a->vd, pass, MO_64);
30456106af3aSPeter Maydell             accfn(rd_64, tmp64, rd_64);
30466106af3aSPeter Maydell             tcg_temp_free_i64(tmp64);
30476106af3aSPeter Maydell         }
30480aa8e700SRichard Henderson         write_neon_element64(rd_64, a->vd, pass, MO_64);
30496106af3aSPeter Maydell         tcg_temp_free_i64(rd_64);
30506106af3aSPeter Maydell     }
30516106af3aSPeter Maydell     return true;
30526106af3aSPeter Maydell }
30536106af3aSPeter Maydell 
30546106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a)
30556106af3aSPeter Maydell {
30566106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
30576106af3aSPeter Maydell         gen_helper_neon_widen_s8,
30586106af3aSPeter Maydell         gen_helper_neon_widen_s16,
30596106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
30606106af3aSPeter Maydell         NULL,
30616106af3aSPeter Maydell     };
30626106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
30636106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
30646106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
30656106af3aSPeter Maydell         tcg_gen_add_i64,
30666106af3aSPeter Maydell         NULL,
30676106af3aSPeter Maydell     };
30686106af3aSPeter Maydell 
30696106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
30706106af3aSPeter Maydell }
30716106af3aSPeter Maydell 
30726106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a)
30736106af3aSPeter Maydell {
30746106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
30756106af3aSPeter Maydell         gen_helper_neon_widen_u8,
30766106af3aSPeter Maydell         gen_helper_neon_widen_u16,
30776106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
30786106af3aSPeter Maydell         NULL,
30796106af3aSPeter Maydell     };
30806106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
30816106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
30826106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
30836106af3aSPeter Maydell         tcg_gen_add_i64,
30846106af3aSPeter Maydell         NULL,
30856106af3aSPeter Maydell     };
30866106af3aSPeter Maydell 
30876106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
30886106af3aSPeter Maydell }
30896106af3aSPeter Maydell 
30906106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a)
30916106af3aSPeter Maydell {
30926106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
30936106af3aSPeter Maydell         gen_helper_neon_widen_s8,
30946106af3aSPeter Maydell         gen_helper_neon_widen_s16,
30956106af3aSPeter Maydell         tcg_gen_ext_i32_i64,
30966106af3aSPeter Maydell         NULL,
30976106af3aSPeter Maydell     };
30986106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
30996106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
31006106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
31016106af3aSPeter Maydell         tcg_gen_add_i64,
31026106af3aSPeter Maydell         NULL,
31036106af3aSPeter Maydell     };
31046106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
31056106af3aSPeter Maydell         gen_helper_neon_addl_u16,
31066106af3aSPeter Maydell         gen_helper_neon_addl_u32,
31076106af3aSPeter Maydell         tcg_gen_add_i64,
31086106af3aSPeter Maydell         NULL,
31096106af3aSPeter Maydell     };
31106106af3aSPeter Maydell 
31116106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
31126106af3aSPeter Maydell                              accfn[a->size]);
31136106af3aSPeter Maydell }
31146106af3aSPeter Maydell 
31156106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
31166106af3aSPeter Maydell {
31176106af3aSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
31186106af3aSPeter Maydell         gen_helper_neon_widen_u8,
31196106af3aSPeter Maydell         gen_helper_neon_widen_u16,
31206106af3aSPeter Maydell         tcg_gen_extu_i32_i64,
31216106af3aSPeter Maydell         NULL,
31226106af3aSPeter Maydell     };
31236106af3aSPeter Maydell     static NeonGenTwo64OpFn * const opfn[] = {
31246106af3aSPeter Maydell         gen_helper_neon_paddl_u16,
31256106af3aSPeter Maydell         gen_helper_neon_paddl_u32,
31266106af3aSPeter Maydell         tcg_gen_add_i64,
31276106af3aSPeter Maydell         NULL,
31286106af3aSPeter Maydell     };
31296106af3aSPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
31306106af3aSPeter Maydell         gen_helper_neon_addl_u16,
31316106af3aSPeter Maydell         gen_helper_neon_addl_u32,
31326106af3aSPeter Maydell         tcg_gen_add_i64,
31336106af3aSPeter Maydell         NULL,
31346106af3aSPeter Maydell     };
31356106af3aSPeter Maydell 
31366106af3aSPeter Maydell     return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
31376106af3aSPeter Maydell                              accfn[a->size]);
31386106af3aSPeter Maydell }
3139567663a2SPeter Maydell 
3140567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr);
3141567663a2SPeter Maydell 
3142567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
3143567663a2SPeter Maydell                        ZipFn *fn)
3144567663a2SPeter Maydell {
3145567663a2SPeter Maydell     TCGv_ptr pd, pm;
3146567663a2SPeter Maydell 
3147567663a2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3148567663a2SPeter Maydell         return false;
3149567663a2SPeter Maydell     }
3150567663a2SPeter Maydell 
3151567663a2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3152567663a2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3153567663a2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3154567663a2SPeter Maydell         return false;
3155567663a2SPeter Maydell     }
3156567663a2SPeter Maydell 
3157567663a2SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3158567663a2SPeter Maydell         return false;
3159567663a2SPeter Maydell     }
3160567663a2SPeter Maydell 
3161567663a2SPeter Maydell     if (!fn) {
3162567663a2SPeter Maydell         /* Bad size or size/q combination */
3163567663a2SPeter Maydell         return false;
3164567663a2SPeter Maydell     }
3165567663a2SPeter Maydell 
3166567663a2SPeter Maydell     if (!vfp_access_check(s)) {
3167567663a2SPeter Maydell         return true;
3168567663a2SPeter Maydell     }
3169567663a2SPeter Maydell 
3170567663a2SPeter Maydell     pd = vfp_reg_ptr(true, a->vd);
3171567663a2SPeter Maydell     pm = vfp_reg_ptr(true, a->vm);
3172567663a2SPeter Maydell     fn(pd, pm);
3173567663a2SPeter Maydell     tcg_temp_free_ptr(pd);
3174567663a2SPeter Maydell     tcg_temp_free_ptr(pm);
3175567663a2SPeter Maydell     return true;
3176567663a2SPeter Maydell }
3177567663a2SPeter Maydell 
3178567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a)
3179567663a2SPeter Maydell {
3180567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3181567663a2SPeter Maydell         {
3182567663a2SPeter Maydell             gen_helper_neon_unzip8,
3183567663a2SPeter Maydell             gen_helper_neon_unzip16,
3184567663a2SPeter Maydell             NULL,
3185567663a2SPeter Maydell             NULL,
3186567663a2SPeter Maydell         }, {
3187567663a2SPeter Maydell             gen_helper_neon_qunzip8,
3188567663a2SPeter Maydell             gen_helper_neon_qunzip16,
3189567663a2SPeter Maydell             gen_helper_neon_qunzip32,
3190567663a2SPeter Maydell             NULL,
3191567663a2SPeter Maydell         }
3192567663a2SPeter Maydell     };
3193567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3194567663a2SPeter Maydell }
3195567663a2SPeter Maydell 
3196567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a)
3197567663a2SPeter Maydell {
3198567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
3199567663a2SPeter Maydell         {
3200567663a2SPeter Maydell             gen_helper_neon_zip8,
3201567663a2SPeter Maydell             gen_helper_neon_zip16,
3202567663a2SPeter Maydell             NULL,
3203567663a2SPeter Maydell             NULL,
3204567663a2SPeter Maydell         }, {
3205567663a2SPeter Maydell             gen_helper_neon_qzip8,
3206567663a2SPeter Maydell             gen_helper_neon_qzip16,
3207567663a2SPeter Maydell             gen_helper_neon_qzip32,
3208567663a2SPeter Maydell             NULL,
3209567663a2SPeter Maydell         }
3210567663a2SPeter Maydell     };
3211567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
3212567663a2SPeter Maydell }
32133882bdacSPeter Maydell 
32143882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a,
32153882bdacSPeter Maydell                      NeonGenNarrowEnvFn *narrowfn)
32163882bdacSPeter Maydell {
32173882bdacSPeter Maydell     TCGv_i64 rm;
32183882bdacSPeter Maydell     TCGv_i32 rd0, rd1;
32193882bdacSPeter Maydell 
32203882bdacSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
32213882bdacSPeter Maydell         return false;
32223882bdacSPeter Maydell     }
32233882bdacSPeter Maydell 
32243882bdacSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
32253882bdacSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
32263882bdacSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
32273882bdacSPeter Maydell         return false;
32283882bdacSPeter Maydell     }
32293882bdacSPeter Maydell 
32303882bdacSPeter Maydell     if (a->vm & 1) {
32313882bdacSPeter Maydell         return false;
32323882bdacSPeter Maydell     }
32333882bdacSPeter Maydell 
32343882bdacSPeter Maydell     if (!narrowfn) {
32353882bdacSPeter Maydell         return false;
32363882bdacSPeter Maydell     }
32373882bdacSPeter Maydell 
32383882bdacSPeter Maydell     if (!vfp_access_check(s)) {
32393882bdacSPeter Maydell         return true;
32403882bdacSPeter Maydell     }
32413882bdacSPeter Maydell 
32423882bdacSPeter Maydell     rm = tcg_temp_new_i64();
32433882bdacSPeter Maydell     rd0 = tcg_temp_new_i32();
32443882bdacSPeter Maydell     rd1 = tcg_temp_new_i32();
32453882bdacSPeter Maydell 
32460aa8e700SRichard Henderson     read_neon_element64(rm, a->vm, 0, MO_64);
32473882bdacSPeter Maydell     narrowfn(rd0, cpu_env, rm);
32480aa8e700SRichard Henderson     read_neon_element64(rm, a->vm, 1, MO_64);
32493882bdacSPeter Maydell     narrowfn(rd1, cpu_env, rm);
3250a712266fSRichard Henderson     write_neon_element32(rd0, a->vd, 0, MO_32);
3251a712266fSRichard Henderson     write_neon_element32(rd1, a->vd, 1, MO_32);
3252a712266fSRichard Henderson     tcg_temp_free_i32(rd0);
3253a712266fSRichard Henderson     tcg_temp_free_i32(rd1);
32543882bdacSPeter Maydell     tcg_temp_free_i64(rm);
32553882bdacSPeter Maydell     return true;
32563882bdacSPeter Maydell }
32573882bdacSPeter Maydell 
32583882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC)                                    \
32593882bdacSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
32603882bdacSPeter Maydell     {                                                           \
32613882bdacSPeter Maydell         static NeonGenNarrowEnvFn * const narrowfn[] = {        \
32623882bdacSPeter Maydell             FUNC##8,                                            \
32633882bdacSPeter Maydell             FUNC##16,                                           \
32643882bdacSPeter Maydell             FUNC##32,                                           \
32653882bdacSPeter Maydell             NULL,                                               \
32663882bdacSPeter Maydell         };                                                      \
32673882bdacSPeter Maydell         return do_vmovn(s, a, narrowfn[a->size]);               \
32683882bdacSPeter Maydell     }
32693882bdacSPeter Maydell 
32703882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u)
32713882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
32723882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
32733882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
3274749e2be3SPeter Maydell 
3275749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
3276749e2be3SPeter Maydell {
3277749e2be3SPeter Maydell     TCGv_i32 rm0, rm1;
3278749e2be3SPeter Maydell     TCGv_i64 rd;
3279749e2be3SPeter Maydell     static NeonGenWidenFn * const widenfns[] = {
3280749e2be3SPeter Maydell         gen_helper_neon_widen_u8,
3281749e2be3SPeter Maydell         gen_helper_neon_widen_u16,
3282749e2be3SPeter Maydell         tcg_gen_extu_i32_i64,
3283749e2be3SPeter Maydell         NULL,
3284749e2be3SPeter Maydell     };
3285749e2be3SPeter Maydell     NeonGenWidenFn *widenfn = widenfns[a->size];
3286749e2be3SPeter Maydell 
3287749e2be3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3288749e2be3SPeter Maydell         return false;
3289749e2be3SPeter Maydell     }
3290749e2be3SPeter Maydell 
3291749e2be3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3292749e2be3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3293749e2be3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3294749e2be3SPeter Maydell         return false;
3295749e2be3SPeter Maydell     }
3296749e2be3SPeter Maydell 
3297749e2be3SPeter Maydell     if (a->vd & 1) {
3298749e2be3SPeter Maydell         return false;
3299749e2be3SPeter Maydell     }
3300749e2be3SPeter Maydell 
3301749e2be3SPeter Maydell     if (!widenfn) {
3302749e2be3SPeter Maydell         return false;
3303749e2be3SPeter Maydell     }
3304749e2be3SPeter Maydell 
3305749e2be3SPeter Maydell     if (!vfp_access_check(s)) {
3306749e2be3SPeter Maydell         return true;
3307749e2be3SPeter Maydell     }
3308749e2be3SPeter Maydell 
3309749e2be3SPeter Maydell     rd = tcg_temp_new_i64();
3310a712266fSRichard Henderson     rm0 = tcg_temp_new_i32();
3311a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
3312749e2be3SPeter Maydell 
3313a712266fSRichard Henderson     read_neon_element32(rm0, a->vm, 0, MO_32);
3314a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 1, MO_32);
3315749e2be3SPeter Maydell 
3316749e2be3SPeter Maydell     widenfn(rd, rm0);
3317749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
33180aa8e700SRichard Henderson     write_neon_element64(rd, a->vd, 0, MO_64);
3319749e2be3SPeter Maydell     widenfn(rd, rm1);
3320749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
33210aa8e700SRichard Henderson     write_neon_element64(rd, a->vd, 1, MO_64);
3322749e2be3SPeter Maydell 
3323749e2be3SPeter Maydell     tcg_temp_free_i64(rd);
3324749e2be3SPeter Maydell     tcg_temp_free_i32(rm0);
3325749e2be3SPeter Maydell     tcg_temp_free_i32(rm1);
3326749e2be3SPeter Maydell     return true;
3327749e2be3SPeter Maydell }
3328654a5173SPeter Maydell 
3329654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
3330654a5173SPeter Maydell {
3331654a5173SPeter Maydell     TCGv_ptr fpst;
3332654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3333654a5173SPeter Maydell 
3334654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3335654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3336654a5173SPeter Maydell         return false;
3337654a5173SPeter Maydell     }
3338654a5173SPeter Maydell 
3339654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3340654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3341654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3342654a5173SPeter Maydell         return false;
3343654a5173SPeter Maydell     }
3344654a5173SPeter Maydell 
3345654a5173SPeter Maydell     if ((a->vm & 1) || (a->size != 1)) {
3346654a5173SPeter Maydell         return false;
3347654a5173SPeter Maydell     }
3348654a5173SPeter Maydell 
3349654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3350654a5173SPeter Maydell         return true;
3351654a5173SPeter Maydell     }
3352654a5173SPeter Maydell 
3353a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3354654a5173SPeter Maydell     ahp = get_ahp_flag();
3355a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
3356a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 0, MO_32);
3357654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3358a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
3359a712266fSRichard Henderson     read_neon_element32(tmp2, a->vm, 1, MO_32);
3360654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
3361654a5173SPeter Maydell     tcg_gen_shli_i32(tmp2, tmp2, 16);
3362654a5173SPeter Maydell     tcg_gen_or_i32(tmp2, tmp2, tmp);
3363a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 2, MO_32);
3364654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
3365a712266fSRichard Henderson     tmp3 = tcg_temp_new_i32();
3366a712266fSRichard Henderson     read_neon_element32(tmp3, a->vm, 3, MO_32);
3367a712266fSRichard Henderson     write_neon_element32(tmp2, a->vd, 0, MO_32);
3368a712266fSRichard Henderson     tcg_temp_free_i32(tmp2);
3369654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
3370654a5173SPeter Maydell     tcg_gen_shli_i32(tmp3, tmp3, 16);
3371654a5173SPeter Maydell     tcg_gen_or_i32(tmp3, tmp3, tmp);
3372a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 1, MO_32);
3373a712266fSRichard Henderson     tcg_temp_free_i32(tmp3);
3374654a5173SPeter Maydell     tcg_temp_free_i32(tmp);
3375654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3376654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3377654a5173SPeter Maydell 
3378654a5173SPeter Maydell     return true;
3379654a5173SPeter Maydell }
3380654a5173SPeter Maydell 
3381654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
3382654a5173SPeter Maydell {
3383654a5173SPeter Maydell     TCGv_ptr fpst;
3384654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
3385654a5173SPeter Maydell 
3386654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
3387654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
3388654a5173SPeter Maydell         return false;
3389654a5173SPeter Maydell     }
3390654a5173SPeter Maydell 
3391654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3392654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3393654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3394654a5173SPeter Maydell         return false;
3395654a5173SPeter Maydell     }
3396654a5173SPeter Maydell 
3397654a5173SPeter Maydell     if ((a->vd & 1) || (a->size != 1)) {
3398654a5173SPeter Maydell         return false;
3399654a5173SPeter Maydell     }
3400654a5173SPeter Maydell 
3401654a5173SPeter Maydell     if (!vfp_access_check(s)) {
3402654a5173SPeter Maydell         return true;
3403654a5173SPeter Maydell     }
3404654a5173SPeter Maydell 
3405a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
3406654a5173SPeter Maydell     ahp = get_ahp_flag();
3407654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
3408a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
3409a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
3410a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 0, MO_32);
3411a712266fSRichard Henderson     read_neon_element32(tmp2, a->vm, 1, MO_32);
3412654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp);
3413654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3414a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 0, MO_32);
3415654a5173SPeter Maydell     tcg_gen_shri_i32(tmp, tmp, 16);
3416654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
3417a712266fSRichard Henderson     write_neon_element32(tmp, a->vd, 1, MO_32);
3418a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
3419654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp2);
3420654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
3421a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 2, MO_32);
3422a712266fSRichard Henderson     tcg_temp_free_i32(tmp3);
3423654a5173SPeter Maydell     tcg_gen_shri_i32(tmp2, tmp2, 16);
3424654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
3425a712266fSRichard Henderson     write_neon_element32(tmp2, a->vd, 3, MO_32);
3426a712266fSRichard Henderson     tcg_temp_free_i32(tmp2);
3427654a5173SPeter Maydell     tcg_temp_free_i32(ahp);
3428654a5173SPeter Maydell     tcg_temp_free_ptr(fpst);
3429654a5173SPeter Maydell 
3430654a5173SPeter Maydell     return true;
3431654a5173SPeter Maydell }
343275153179SPeter Maydell 
343375153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
343475153179SPeter Maydell {
343575153179SPeter Maydell     int vec_size = a->q ? 16 : 8;
3436015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
3437015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
343875153179SPeter Maydell 
343975153179SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
344075153179SPeter Maydell         return false;
344175153179SPeter Maydell     }
344275153179SPeter Maydell 
344375153179SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
344475153179SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
344575153179SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
344675153179SPeter Maydell         return false;
344775153179SPeter Maydell     }
344875153179SPeter Maydell 
344975153179SPeter Maydell     if (a->size == 3) {
345075153179SPeter Maydell         return false;
345175153179SPeter Maydell     }
345275153179SPeter Maydell 
345375153179SPeter Maydell     if ((a->vd | a->vm) & a->q) {
345475153179SPeter Maydell         return false;
345575153179SPeter Maydell     }
345675153179SPeter Maydell 
345775153179SPeter Maydell     if (!vfp_access_check(s)) {
345875153179SPeter Maydell         return true;
345975153179SPeter Maydell     }
346075153179SPeter Maydell 
346175153179SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size);
346275153179SPeter Maydell 
346375153179SPeter Maydell     return true;
346475153179SPeter Maydell }
346575153179SPeter Maydell 
346675153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN)                                  \
346775153179SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
346875153179SPeter Maydell     {                                                           \
346975153179SPeter Maydell         return do_2misc_vec(s, a, FN);                          \
347075153179SPeter Maydell     }
347175153179SPeter Maydell 
347275153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg)
347375153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs)
347475153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0)
347575153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
347675153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
347775153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
347875153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
347975153179SPeter Maydell 
348075153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a)
348175153179SPeter Maydell {
348275153179SPeter Maydell     if (a->size != 0) {
348375153179SPeter Maydell         return false;
348475153179SPeter Maydell     }
348575153179SPeter Maydell     return do_2misc_vec(s, a, tcg_gen_gvec_not);
348675153179SPeter Maydell }
34870b30dd5bSPeter Maydell 
34880b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA)                          \
34890b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
34900b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
34910b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
34920b30dd5bSPeter Maydell     {                                                                   \
34930b30dd5bSPeter Maydell         tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz,        \
34940b30dd5bSPeter Maydell                            DATA, FUNC);                                 \
34950b30dd5bSPeter Maydell     }
34960b30dd5bSPeter Maydell 
34970b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA)                          \
34980b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
34990b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
35000b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
35010b30dd5bSPeter Maydell     {                                                                   \
35020b30dd5bSPeter Maydell         tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC);   \
35030b30dd5bSPeter Maydell     }
35040b30dd5bSPeter Maydell 
35050b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0)
35060b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1)
35070b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0)
35080b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1)
35090b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0)
35100b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0)
35110b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0)
35120b30dd5bSPeter Maydell 
35130b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE)                       \
35140b30dd5bSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
35150b30dd5bSPeter Maydell     {                                                           \
35160b30dd5bSPeter Maydell         if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) {  \
35170b30dd5bSPeter Maydell             return false;                                       \
35180b30dd5bSPeter Maydell         }                                                       \
35190b30dd5bSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                  \
35200b30dd5bSPeter Maydell     }
35210b30dd5bSPeter Maydell 
35220b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0)
35230b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0)
35240b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0)
35250b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
35260b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
35270b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
35280b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
352989668082SPeter Maydell 
353089668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
353189668082SPeter Maydell {
3532a712266fSRichard Henderson     TCGv_i32 tmp;
353389668082SPeter Maydell     int pass;
353489668082SPeter Maydell 
353589668082SPeter Maydell     /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
353689668082SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
353789668082SPeter Maydell         return false;
353889668082SPeter Maydell     }
353989668082SPeter Maydell 
354089668082SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
354189668082SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
354289668082SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
354389668082SPeter Maydell         return false;
354489668082SPeter Maydell     }
354589668082SPeter Maydell 
354689668082SPeter Maydell     if (!fn) {
354789668082SPeter Maydell         return false;
354889668082SPeter Maydell     }
354989668082SPeter Maydell 
355089668082SPeter Maydell     if ((a->vd | a->vm) & a->q) {
355189668082SPeter Maydell         return false;
355289668082SPeter Maydell     }
355389668082SPeter Maydell 
355489668082SPeter Maydell     if (!vfp_access_check(s)) {
355589668082SPeter Maydell         return true;
355689668082SPeter Maydell     }
355789668082SPeter Maydell 
3558a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
355989668082SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
3560a712266fSRichard Henderson         read_neon_element32(tmp, a->vm, pass, MO_32);
356189668082SPeter Maydell         fn(tmp, tmp);
3562a712266fSRichard Henderson         write_neon_element32(tmp, a->vd, pass, MO_32);
356389668082SPeter Maydell     }
3564a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
356589668082SPeter Maydell 
356689668082SPeter Maydell     return true;
356789668082SPeter Maydell }
356889668082SPeter Maydell 
356989668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a)
357089668082SPeter Maydell {
357189668082SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
357289668082SPeter Maydell         tcg_gen_bswap32_i32,
357389668082SPeter Maydell         gen_swap_half,
357489668082SPeter Maydell         NULL,
357589668082SPeter Maydell         NULL,
357689668082SPeter Maydell     };
357789668082SPeter Maydell     return do_2misc(s, a, fn[a->size]);
357889668082SPeter Maydell }
357989668082SPeter Maydell 
358089668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a)
358189668082SPeter Maydell {
358289668082SPeter Maydell     if (a->size != 0) {
358389668082SPeter Maydell         return false;
358489668082SPeter Maydell     }
358589668082SPeter Maydell     return do_2misc(s, a, gen_rev16);
358689668082SPeter Maydell }
358784eae770SPeter Maydell 
358884eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a)
358984eae770SPeter Maydell {
359084eae770SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
359184eae770SPeter Maydell         gen_helper_neon_cls_s8,
359284eae770SPeter Maydell         gen_helper_neon_cls_s16,
359384eae770SPeter Maydell         gen_helper_neon_cls_s32,
359484eae770SPeter Maydell         NULL,
359584eae770SPeter Maydell     };
359684eae770SPeter Maydell     return do_2misc(s, a, fn[a->size]);
359784eae770SPeter Maydell }
359884eae770SPeter Maydell 
359984eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm)
360084eae770SPeter Maydell {
360184eae770SPeter Maydell     tcg_gen_clzi_i32(rd, rm, 32);
360284eae770SPeter Maydell }
360384eae770SPeter Maydell 
360484eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a)
360584eae770SPeter Maydell {
360684eae770SPeter Maydell     static NeonGenOneOpFn * const fn[] = {
360784eae770SPeter Maydell         gen_helper_neon_clz_u8,
360884eae770SPeter Maydell         gen_helper_neon_clz_u16,
360984eae770SPeter Maydell         do_VCLZ_32,
361084eae770SPeter Maydell         NULL,
361184eae770SPeter Maydell     };
361284eae770SPeter Maydell     return do_2misc(s, a, fn[a->size]);
361384eae770SPeter Maydell }
361484eae770SPeter Maydell 
361584eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a)
361684eae770SPeter Maydell {
361784eae770SPeter Maydell     if (a->size != 0) {
361884eae770SPeter Maydell         return false;
361984eae770SPeter Maydell     }
362084eae770SPeter Maydell     return do_2misc(s, a, gen_helper_neon_cnt_u8);
362184eae770SPeter Maydell }
362284eae770SPeter Maydell 
36232b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
36242b70d8cdSPeter Maydell                        uint32_t oprsz, uint32_t maxsz)
36252b70d8cdSPeter Maydell {
36262b70d8cdSPeter Maydell     tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs,
36272b70d8cdSPeter Maydell                       vece == MO_16 ? 0x7fff : 0x7fffffff,
36282b70d8cdSPeter Maydell                       oprsz, maxsz);
36292b70d8cdSPeter Maydell }
36302b70d8cdSPeter Maydell 
363184eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
363284eae770SPeter Maydell {
36332b70d8cdSPeter Maydell     if (a->size == MO_16) {
36342b70d8cdSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
363584eae770SPeter Maydell             return false;
363684eae770SPeter Maydell         }
36372b70d8cdSPeter Maydell     } else if (a->size != MO_32) {
36382b70d8cdSPeter Maydell         return false;
36392b70d8cdSPeter Maydell     }
36402b70d8cdSPeter Maydell     return do_2misc_vec(s, a, gen_VABS_F);
36412b70d8cdSPeter Maydell }
36422b70d8cdSPeter Maydell 
36432b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
36442b70d8cdSPeter Maydell                        uint32_t oprsz, uint32_t maxsz)
36452b70d8cdSPeter Maydell {
36462b70d8cdSPeter Maydell     tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs,
36472b70d8cdSPeter Maydell                       vece == MO_16 ? 0x8000 : 0x80000000,
36482b70d8cdSPeter Maydell                       oprsz, maxsz);
364984eae770SPeter Maydell }
365084eae770SPeter Maydell 
365184eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
365284eae770SPeter Maydell {
36532b70d8cdSPeter Maydell     if (a->size == MO_16) {
36542b70d8cdSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
365584eae770SPeter Maydell             return false;
365684eae770SPeter Maydell         }
36572b70d8cdSPeter Maydell     } else if (a->size != MO_32) {
36582b70d8cdSPeter Maydell         return false;
36592b70d8cdSPeter Maydell     }
36602b70d8cdSPeter Maydell     return do_2misc_vec(s, a, gen_VNEG_F);
366184eae770SPeter Maydell }
366284eae770SPeter Maydell 
366384eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
366484eae770SPeter Maydell {
366584eae770SPeter Maydell     if (a->size != 2) {
366684eae770SPeter Maydell         return false;
366784eae770SPeter Maydell     }
366884eae770SPeter Maydell     return do_2misc(s, a, gen_helper_recpe_u32);
366984eae770SPeter Maydell }
367084eae770SPeter Maydell 
367184eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
367284eae770SPeter Maydell {
367384eae770SPeter Maydell     if (a->size != 2) {
367484eae770SPeter Maydell         return false;
367584eae770SPeter Maydell     }
367684eae770SPeter Maydell     return do_2misc(s, a, gen_helper_rsqrte_u32);
367784eae770SPeter Maydell }
36784936f38aSPeter Maydell 
36794936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \
36804936f38aSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 m)        \
36814936f38aSPeter Maydell     {                                                   \
36824936f38aSPeter Maydell         FUNC(d, cpu_env, m);                            \
36834936f38aSPeter Maydell     }
36844936f38aSPeter Maydell 
36854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8)
36864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16)
36874936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32)
36884936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8)
36894936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16)
36904936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32)
36914936f38aSPeter Maydell 
36924936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a)
36934936f38aSPeter Maydell {
36944936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
36954936f38aSPeter Maydell         gen_VQABS_s8,
36964936f38aSPeter Maydell         gen_VQABS_s16,
36974936f38aSPeter Maydell         gen_VQABS_s32,
36984936f38aSPeter Maydell         NULL,
36994936f38aSPeter Maydell     };
37004936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
37014936f38aSPeter Maydell }
37024936f38aSPeter Maydell 
37034936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a)
37044936f38aSPeter Maydell {
37054936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
37064936f38aSPeter Maydell         gen_VQNEG_s8,
37074936f38aSPeter Maydell         gen_VQNEG_s16,
37084936f38aSPeter Maydell         gen_VQNEG_s32,
37094936f38aSPeter Maydell         NULL,
37104936f38aSPeter Maydell     };
37114936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
37124936f38aSPeter Maydell }
37133e96b205SPeter Maydell 
37144a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC)                             \
37154a15d9a3SPeter Maydell     static void gen_##INSN(unsigned vece, uint32_t rd_ofs,              \
37164a15d9a3SPeter Maydell                            uint32_t rm_ofs,                             \
37174a15d9a3SPeter Maydell                            uint32_t oprsz, uint32_t maxsz)              \
37184a15d9a3SPeter Maydell     {                                                                   \
37194a15d9a3SPeter Maydell         static gen_helper_gvec_2_ptr * const fns[4] = {                 \
37204a15d9a3SPeter Maydell             NULL, HFUNC, SFUNC, NULL,                                   \
37214a15d9a3SPeter Maydell         };                                                              \
37224a15d9a3SPeter Maydell         TCGv_ptr fpst;                                                  \
37234a15d9a3SPeter Maydell         fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD);   \
37244a15d9a3SPeter Maydell         tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0,       \
37254a15d9a3SPeter Maydell                            fns[vece]);                                  \
37264a15d9a3SPeter Maydell         tcg_temp_free_ptr(fpst);                                        \
37274a15d9a3SPeter Maydell     }                                                                   \
37284a15d9a3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)             \
37294a15d9a3SPeter Maydell     {                                                                   \
37304a15d9a3SPeter Maydell         if (a->size == MO_16) {                                         \
37314a15d9a3SPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
37324a15d9a3SPeter Maydell                 return false;                                           \
37334a15d9a3SPeter Maydell             }                                                           \
37344a15d9a3SPeter Maydell         } else if (a->size != MO_32) {                                  \
37354a15d9a3SPeter Maydell             return false;                                               \
37364a15d9a3SPeter Maydell         }                                                               \
37374a15d9a3SPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                          \
37384a15d9a3SPeter Maydell     }
37394a15d9a3SPeter Maydell 
37404a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s)
37414a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s)
3742635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s)
3743635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s)
3744635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s)
3745635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s)
3746635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s)
37477782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos)
37487782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos)
37497782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs)
37507782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs)
37514a15d9a3SPeter Maydell 
375223afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s)
375323afcdd2SPeter Maydell 
37543e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a)
37553e96b205SPeter Maydell {
37563e96b205SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
37573e96b205SPeter Maydell         return false;
37583e96b205SPeter Maydell     }
375923afcdd2SPeter Maydell     return trans_VRINTX_impl(s, a);
37603e96b205SPeter Maydell }
3761baa59323SPeter Maydell 
3762ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP)                                   \
3763ca88a6efSPeter Maydell     static void gen_##INSN(unsigned vece, uint32_t rd_ofs,              \
3764ca88a6efSPeter Maydell                            uint32_t rm_ofs,                             \
3765ca88a6efSPeter Maydell                            uint32_t oprsz, uint32_t maxsz)              \
3766ca88a6efSPeter Maydell     {                                                                   \
3767ca88a6efSPeter Maydell         static gen_helper_gvec_2_ptr * const fns[4] = {                 \
3768ca88a6efSPeter Maydell             NULL,                                                       \
3769ca88a6efSPeter Maydell             gen_helper_gvec_##OP##h,                                    \
3770ca88a6efSPeter Maydell             gen_helper_gvec_##OP##s,                                    \
3771ca88a6efSPeter Maydell             NULL,                                                       \
3772ca88a6efSPeter Maydell         };                                                              \
3773ca88a6efSPeter Maydell         TCGv_ptr fpst;                                                  \
3774ca88a6efSPeter Maydell         fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD);       \
3775ca88a6efSPeter Maydell         tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz,          \
3776ca88a6efSPeter Maydell                            arm_rmode_to_sf(RMODE), fns[vece]);          \
3777ca88a6efSPeter Maydell         tcg_temp_free_ptr(fpst);                                        \
3778ca88a6efSPeter Maydell     }                                                                   \
3779a183d5fbSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)             \
3780a183d5fbSPeter Maydell     {                                                                   \
3781ca88a6efSPeter Maydell         if (!arm_dc_feature(s, ARM_FEATURE_V8)) {                       \
3782ca88a6efSPeter Maydell             return false;                                               \
3783ca88a6efSPeter Maydell         }                                                               \
3784ca88a6efSPeter Maydell         if (a->size == MO_16) {                                         \
3785ca88a6efSPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
3786ca88a6efSPeter Maydell                 return false;                                           \
3787ca88a6efSPeter Maydell             }                                                           \
3788ca88a6efSPeter Maydell         } else if (a->size != MO_32) {                                  \
3789ca88a6efSPeter Maydell             return false;                                               \
3790ca88a6efSPeter Maydell         }                                                               \
3791ca88a6efSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                          \
3792a183d5fbSPeter Maydell     }
3793a183d5fbSPeter Maydell 
3794ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u)
3795ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s)
3796ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u)
3797ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s)
3798ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u)
3799ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s)
3800ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u)
3801ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s)
38028ab3a227SPeter Maydell 
380318725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_)
380418725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_)
380518725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_)
380618725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_)
380718725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_)
380818725916SPeter Maydell 
38098ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a)
38108ab3a227SPeter Maydell {
38118ab3a227SPeter Maydell     TCGv_i64 rm, rd;
38128ab3a227SPeter Maydell     int pass;
38138ab3a227SPeter Maydell 
38148ab3a227SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
38158ab3a227SPeter Maydell         return false;
38168ab3a227SPeter Maydell     }
38178ab3a227SPeter Maydell 
38188ab3a227SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
38198ab3a227SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
38208ab3a227SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
38218ab3a227SPeter Maydell         return false;
38228ab3a227SPeter Maydell     }
38238ab3a227SPeter Maydell 
38248ab3a227SPeter Maydell     if (a->size != 0) {
38258ab3a227SPeter Maydell         return false;
38268ab3a227SPeter Maydell     }
38278ab3a227SPeter Maydell 
38288ab3a227SPeter Maydell     if ((a->vd | a->vm) & a->q) {
38298ab3a227SPeter Maydell         return false;
38308ab3a227SPeter Maydell     }
38318ab3a227SPeter Maydell 
38328ab3a227SPeter Maydell     if (!vfp_access_check(s)) {
38338ab3a227SPeter Maydell         return true;
38348ab3a227SPeter Maydell     }
38358ab3a227SPeter Maydell 
38368ab3a227SPeter Maydell     rm = tcg_temp_new_i64();
38378ab3a227SPeter Maydell     rd = tcg_temp_new_i64();
38388ab3a227SPeter Maydell     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
38390aa8e700SRichard Henderson         read_neon_element64(rm, a->vm, pass, MO_64);
38400aa8e700SRichard Henderson         read_neon_element64(rd, a->vd, pass, MO_64);
38410aa8e700SRichard Henderson         write_neon_element64(rm, a->vd, pass, MO_64);
38420aa8e700SRichard Henderson         write_neon_element64(rd, a->vm, pass, MO_64);
38438ab3a227SPeter Maydell     }
38448ab3a227SPeter Maydell     tcg_temp_free_i64(rm);
38458ab3a227SPeter Maydell     tcg_temp_free_i64(rd);
38468ab3a227SPeter Maydell 
38478ab3a227SPeter Maydell     return true;
38488ab3a227SPeter Maydell }
3849d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
3850d4366190SPeter Maydell {
3851d4366190SPeter Maydell     TCGv_i32 rd, tmp;
3852d4366190SPeter Maydell 
3853d4366190SPeter Maydell     rd = tcg_temp_new_i32();
3854d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
3855d4366190SPeter Maydell 
3856d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 8);
3857d4366190SPeter Maydell     tcg_gen_andi_i32(rd, rd, 0xff00ff00);
3858d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
3859d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
3860d4366190SPeter Maydell 
3861d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 8);
3862d4366190SPeter Maydell     tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
3863d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
3864d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
3865d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
3866d4366190SPeter Maydell 
3867d4366190SPeter Maydell     tcg_temp_free_i32(tmp);
3868d4366190SPeter Maydell     tcg_temp_free_i32(rd);
3869d4366190SPeter Maydell }
3870d4366190SPeter Maydell 
3871d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
3872d4366190SPeter Maydell {
3873d4366190SPeter Maydell     TCGv_i32 rd, tmp;
3874d4366190SPeter Maydell 
3875d4366190SPeter Maydell     rd = tcg_temp_new_i32();
3876d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
3877d4366190SPeter Maydell 
3878d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 16);
3879d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0xffff);
3880d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
3881d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 16);
3882d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xffff0000);
3883d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
3884d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
3885d4366190SPeter Maydell 
3886d4366190SPeter Maydell     tcg_temp_free_i32(tmp);
3887d4366190SPeter Maydell     tcg_temp_free_i32(rd);
3888d4366190SPeter Maydell }
3889d4366190SPeter Maydell 
3890d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a)
3891d4366190SPeter Maydell {
3892d4366190SPeter Maydell     TCGv_i32 tmp, tmp2;
3893d4366190SPeter Maydell     int pass;
3894d4366190SPeter Maydell 
3895d4366190SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3896d4366190SPeter Maydell         return false;
3897d4366190SPeter Maydell     }
3898d4366190SPeter Maydell 
3899d4366190SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3900d4366190SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3901d4366190SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3902d4366190SPeter Maydell         return false;
3903d4366190SPeter Maydell     }
3904d4366190SPeter Maydell 
3905d4366190SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3906d4366190SPeter Maydell         return false;
3907d4366190SPeter Maydell     }
3908d4366190SPeter Maydell 
3909d4366190SPeter Maydell     if (a->size == 3) {
3910d4366190SPeter Maydell         return false;
3911d4366190SPeter Maydell     }
3912d4366190SPeter Maydell 
3913d4366190SPeter Maydell     if (!vfp_access_check(s)) {
3914d4366190SPeter Maydell         return true;
3915d4366190SPeter Maydell     }
3916d4366190SPeter Maydell 
3917a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
3918a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
3919a712266fSRichard Henderson     if (a->size == MO_32) {
3920d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) {
3921a712266fSRichard Henderson             read_neon_element32(tmp, a->vm, pass, MO_32);
3922a712266fSRichard Henderson             read_neon_element32(tmp2, a->vd, pass + 1, MO_32);
3923a712266fSRichard Henderson             write_neon_element32(tmp2, a->vm, pass, MO_32);
3924a712266fSRichard Henderson             write_neon_element32(tmp, a->vd, pass + 1, MO_32);
3925d4366190SPeter Maydell         }
3926d4366190SPeter Maydell     } else {
3927d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
3928a712266fSRichard Henderson             read_neon_element32(tmp, a->vm, pass, MO_32);
3929a712266fSRichard Henderson             read_neon_element32(tmp2, a->vd, pass, MO_32);
3930a712266fSRichard Henderson             if (a->size == MO_8) {
3931d4366190SPeter Maydell                 gen_neon_trn_u8(tmp, tmp2);
3932d4366190SPeter Maydell             } else {
3933d4366190SPeter Maydell                 gen_neon_trn_u16(tmp, tmp2);
3934d4366190SPeter Maydell             }
3935a712266fSRichard Henderson             write_neon_element32(tmp2, a->vm, pass, MO_32);
3936a712266fSRichard Henderson             write_neon_element32(tmp, a->vd, pass, MO_32);
3937d4366190SPeter Maydell         }
3938d4366190SPeter Maydell     }
3939a712266fSRichard Henderson     tcg_temp_free_i32(tmp);
3940a712266fSRichard Henderson     tcg_temp_free_i32(tmp2);
3941d4366190SPeter Maydell     return true;
3942d4366190SPeter Maydell }
3943