xref: /qemu/target/arm/tcg/translate-neon.c (revision 8710a43de1268948bfa2e5b3cc77504246dd6d20)
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 
234800b852SPeter Maydell #include "qemu/osdep.h"
244800b852SPeter Maydell #include "translate.h"
254800b852SPeter Maydell #include "translate-a32.h"
26625e3dd4SPeter Maydell 
27625e3dd4SPeter Maydell /* Include the generated Neon decoder */
28139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc"
29139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc"
30139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc"
31afff8de0SPeter Maydell 
vfp_reg_ptr(bool dp,int reg)32eb554d61SPeter Maydell static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
33eb554d61SPeter Maydell {
34eb554d61SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
35ad75a51eSRichard Henderson     tcg_gen_addi_ptr(ret, tcg_env, vfp_reg_offset(dp, reg));
36eb554d61SPeter Maydell     return ret;
37eb554d61SPeter Maydell }
38eb554d61SPeter Maydell 
neon_load_element(TCGv_i32 var,int reg,int ele,MemOp mop)396fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
406fb57878SPeter Maydell {
416fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
426fb57878SPeter Maydell 
436fb57878SPeter Maydell     switch (mop) {
446fb57878SPeter Maydell     case MO_UB:
45ad75a51eSRichard Henderson         tcg_gen_ld8u_i32(var, tcg_env, offset);
466fb57878SPeter Maydell         break;
476fb57878SPeter Maydell     case MO_UW:
48ad75a51eSRichard Henderson         tcg_gen_ld16u_i32(var, tcg_env, offset);
496fb57878SPeter Maydell         break;
506fb57878SPeter Maydell     case MO_UL:
51ad75a51eSRichard Henderson         tcg_gen_ld_i32(var, tcg_env, offset);
526fb57878SPeter Maydell         break;
536fb57878SPeter Maydell     default:
546fb57878SPeter Maydell         g_assert_not_reached();
556fb57878SPeter Maydell     }
566fb57878SPeter Maydell }
576fb57878SPeter Maydell 
neon_load_element64(TCGv_i64 var,int reg,int ele,MemOp mop)586fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
596fb57878SPeter Maydell {
606fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
616fb57878SPeter Maydell 
626fb57878SPeter Maydell     switch (mop) {
636fb57878SPeter Maydell     case MO_UB:
64ad75a51eSRichard Henderson         tcg_gen_ld8u_i64(var, tcg_env, offset);
656fb57878SPeter Maydell         break;
666fb57878SPeter Maydell     case MO_UW:
67ad75a51eSRichard Henderson         tcg_gen_ld16u_i64(var, tcg_env, offset);
686fb57878SPeter Maydell         break;
696fb57878SPeter Maydell     case MO_UL:
70ad75a51eSRichard Henderson         tcg_gen_ld32u_i64(var, tcg_env, offset);
716fb57878SPeter Maydell         break;
72fc313c64SFrédéric Pétrot     case MO_UQ:
73ad75a51eSRichard Henderson         tcg_gen_ld_i64(var, tcg_env, offset);
746fb57878SPeter Maydell         break;
756fb57878SPeter Maydell     default:
766fb57878SPeter Maydell         g_assert_not_reached();
776fb57878SPeter Maydell     }
786fb57878SPeter Maydell }
796fb57878SPeter Maydell 
neon_store_element(int reg,int ele,MemOp size,TCGv_i32 var)806fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
816fb57878SPeter Maydell {
826fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
836fb57878SPeter Maydell 
846fb57878SPeter Maydell     switch (size) {
856fb57878SPeter Maydell     case MO_8:
86ad75a51eSRichard Henderson         tcg_gen_st8_i32(var, tcg_env, offset);
876fb57878SPeter Maydell         break;
886fb57878SPeter Maydell     case MO_16:
89ad75a51eSRichard Henderson         tcg_gen_st16_i32(var, tcg_env, offset);
906fb57878SPeter Maydell         break;
916fb57878SPeter Maydell     case MO_32:
92ad75a51eSRichard Henderson         tcg_gen_st_i32(var, tcg_env, offset);
936fb57878SPeter Maydell         break;
946fb57878SPeter Maydell     default:
956fb57878SPeter Maydell         g_assert_not_reached();
966fb57878SPeter Maydell     }
976fb57878SPeter Maydell }
986fb57878SPeter Maydell 
neon_store_element64(int reg,int ele,MemOp size,TCGv_i64 var)996fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
1006fb57878SPeter Maydell {
1016fb57878SPeter Maydell     long offset = neon_element_offset(reg, ele, size);
1026fb57878SPeter Maydell 
1036fb57878SPeter Maydell     switch (size) {
1046fb57878SPeter Maydell     case MO_8:
105ad75a51eSRichard Henderson         tcg_gen_st8_i64(var, tcg_env, offset);
1066fb57878SPeter Maydell         break;
1076fb57878SPeter Maydell     case MO_16:
108ad75a51eSRichard Henderson         tcg_gen_st16_i64(var, tcg_env, offset);
1096fb57878SPeter Maydell         break;
1106fb57878SPeter Maydell     case MO_32:
111ad75a51eSRichard Henderson         tcg_gen_st32_i64(var, tcg_env, offset);
1126fb57878SPeter Maydell         break;
1136fb57878SPeter Maydell     case MO_64:
114ad75a51eSRichard Henderson         tcg_gen_st_i64(var, tcg_env, offset);
1156fb57878SPeter Maydell         break;
1166fb57878SPeter Maydell     default:
1176fb57878SPeter Maydell         g_assert_not_reached();
1186fb57878SPeter Maydell     }
1196fb57878SPeter Maydell }
1206fb57878SPeter Maydell 
do_neon_ddda(DisasContext * s,int q,int vd,int vn,int vm,int data,gen_helper_gvec_4 * fn_gvec)1215a46304cSRichard Henderson static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm,
1225a46304cSRichard Henderson                          int data, gen_helper_gvec_4 *fn_gvec)
1235a46304cSRichard Henderson {
1245a46304cSRichard Henderson     /* UNDEF accesses to D16-D31 if they don't exist. */
1255a46304cSRichard Henderson     if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) {
1265a46304cSRichard Henderson         return false;
1275a46304cSRichard Henderson     }
1285a46304cSRichard Henderson 
1295a46304cSRichard Henderson     /*
1305a46304cSRichard Henderson      * UNDEF accesses to odd registers for each bit of Q.
1315a46304cSRichard Henderson      * Q will be 0b111 for all Q-reg instructions, otherwise
1325a46304cSRichard Henderson      * when we have mixed Q- and D-reg inputs.
1335a46304cSRichard Henderson      */
1345a46304cSRichard Henderson     if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) {
1355a46304cSRichard Henderson         return false;
1365a46304cSRichard Henderson     }
1375a46304cSRichard Henderson 
1385a46304cSRichard Henderson     if (!vfp_access_check(s)) {
1395a46304cSRichard Henderson         return true;
1405a46304cSRichard Henderson     }
1415a46304cSRichard Henderson 
1425a46304cSRichard Henderson     int opr_sz = q ? 16 : 8;
1435a46304cSRichard Henderson     tcg_gen_gvec_4_ool(vfp_reg_offset(1, vd),
1445a46304cSRichard Henderson                        vfp_reg_offset(1, vn),
1455a46304cSRichard Henderson                        vfp_reg_offset(1, vm),
1465a46304cSRichard Henderson                        vfp_reg_offset(1, vd),
1475a46304cSRichard Henderson                        opr_sz, opr_sz, data, fn_gvec);
1485a46304cSRichard Henderson     return true;
1495a46304cSRichard Henderson }
1505a46304cSRichard Henderson 
do_neon_ddda_env(DisasContext * s,int q,int vd,int vn,int vm,int data,gen_helper_gvec_4_ptr * fn_gvec)15175a6784dSPeter Maydell static bool do_neon_ddda_env(DisasContext *s, int q, int vd, int vn, int vm,
15275a6784dSPeter Maydell                              int data, gen_helper_gvec_4_ptr *fn_gvec)
15375a6784dSPeter Maydell {
15475a6784dSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
15575a6784dSPeter Maydell     if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) {
15675a6784dSPeter Maydell         return false;
15775a6784dSPeter Maydell     }
15875a6784dSPeter Maydell 
15975a6784dSPeter Maydell     /*
16075a6784dSPeter Maydell      * UNDEF accesses to odd registers for each bit of Q.
16175a6784dSPeter Maydell      * Q will be 0b111 for all Q-reg instructions, otherwise
16275a6784dSPeter Maydell      * when we have mixed Q- and D-reg inputs.
16375a6784dSPeter Maydell      */
16475a6784dSPeter Maydell     if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) {
16575a6784dSPeter Maydell         return false;
16675a6784dSPeter Maydell     }
16775a6784dSPeter Maydell 
16875a6784dSPeter Maydell     if (!vfp_access_check(s)) {
16975a6784dSPeter Maydell         return true;
17075a6784dSPeter Maydell     }
17175a6784dSPeter Maydell 
17275a6784dSPeter Maydell     int opr_sz = q ? 16 : 8;
17375a6784dSPeter Maydell     tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd),
17475a6784dSPeter Maydell                        vfp_reg_offset(1, vn),
17575a6784dSPeter Maydell                        vfp_reg_offset(1, vm),
17675a6784dSPeter Maydell                        vfp_reg_offset(1, vd),
17775a6784dSPeter Maydell                        tcg_env,
17875a6784dSPeter Maydell                        opr_sz, opr_sz, data, fn_gvec);
17975a6784dSPeter Maydell     return true;
18075a6784dSPeter Maydell }
18175a6784dSPeter Maydell 
do_neon_ddda_fpst(DisasContext * s,int q,int vd,int vn,int vm,int data,ARMFPStatusFlavour fp_flavour,gen_helper_gvec_4_ptr * fn_gvec_ptr)182505fce50SRichard Henderson static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm,
183505fce50SRichard Henderson                               int data, ARMFPStatusFlavour fp_flavour,
184505fce50SRichard Henderson                               gen_helper_gvec_4_ptr *fn_gvec_ptr)
185afff8de0SPeter Maydell {
186afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
187505fce50SRichard Henderson     if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) {
188afff8de0SPeter Maydell         return false;
189afff8de0SPeter Maydell     }
190afff8de0SPeter Maydell 
191505fce50SRichard Henderson     /*
192505fce50SRichard Henderson      * UNDEF accesses to odd registers for each bit of Q.
193505fce50SRichard Henderson      * Q will be 0b111 for all Q-reg instructions, otherwise
194505fce50SRichard Henderson      * when we have mixed Q- and D-reg inputs.
195505fce50SRichard Henderson      */
196505fce50SRichard Henderson     if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) {
197afff8de0SPeter Maydell         return false;
198afff8de0SPeter Maydell     }
199afff8de0SPeter Maydell 
200afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
201afff8de0SPeter Maydell         return true;
202afff8de0SPeter Maydell     }
203afff8de0SPeter Maydell 
204505fce50SRichard Henderson     int opr_sz = q ? 16 : 8;
205505fce50SRichard Henderson     TCGv_ptr fpst = fpstatus_ptr(fp_flavour);
206505fce50SRichard Henderson 
207505fce50SRichard Henderson     tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd),
208505fce50SRichard Henderson                        vfp_reg_offset(1, vn),
209505fce50SRichard Henderson                        vfp_reg_offset(1, vm),
210505fce50SRichard Henderson                        vfp_reg_offset(1, vd),
211505fce50SRichard Henderson                        fpst, opr_sz, opr_sz, data, fn_gvec_ptr);
212afff8de0SPeter Maydell     return true;
213afff8de0SPeter Maydell }
21494d5eb7bSPeter Maydell 
trans_VCMLA(DisasContext * s,arg_VCMLA * a)215505fce50SRichard Henderson static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
216505fce50SRichard Henderson {
217505fce50SRichard Henderson     if (!dc_isar_feature(aa32_vcma, s)) {
218505fce50SRichard Henderson         return false;
219505fce50SRichard Henderson     }
220505fce50SRichard Henderson     if (a->size == MO_16) {
221505fce50SRichard Henderson         if (!dc_isar_feature(aa32_fp16_arith, s)) {
222505fce50SRichard Henderson             return false;
223505fce50SRichard Henderson         }
224505fce50SRichard Henderson         return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot,
225505fce50SRichard Henderson                                  FPST_STD_F16, gen_helper_gvec_fcmlah);
226505fce50SRichard Henderson     }
227505fce50SRichard Henderson     return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot,
228505fce50SRichard Henderson                              FPST_STD, gen_helper_gvec_fcmlas);
229505fce50SRichard Henderson }
230505fce50SRichard Henderson 
trans_VCADD(DisasContext * s,arg_VCADD * a)23194d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
23294d5eb7bSPeter Maydell {
23394d5eb7bSPeter Maydell     int opr_sz;
23494d5eb7bSPeter Maydell     TCGv_ptr fpst;
23594d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
23694d5eb7bSPeter Maydell 
23794d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
238d186a485SPeter Maydell         || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) {
23994d5eb7bSPeter Maydell         return false;
24094d5eb7bSPeter Maydell     }
24194d5eb7bSPeter Maydell 
24294d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
24394d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
24494d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
24594d5eb7bSPeter Maydell         return false;
24694d5eb7bSPeter Maydell     }
24794d5eb7bSPeter Maydell 
24894d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
24994d5eb7bSPeter Maydell         return false;
25094d5eb7bSPeter Maydell     }
25194d5eb7bSPeter Maydell 
25294d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
25394d5eb7bSPeter Maydell         return true;
25494d5eb7bSPeter Maydell     }
25594d5eb7bSPeter Maydell 
25694d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
257d186a485SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
258d186a485SPeter Maydell     fn_gvec_ptr = (a->size == MO_16) ?
259d186a485SPeter Maydell         gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds;
26094d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
26194d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
26294d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
26394d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
26494d5eb7bSPeter Maydell                        fn_gvec_ptr);
26594d5eb7bSPeter Maydell     return true;
26694d5eb7bSPeter Maydell }
26732da0e33SPeter Maydell 
trans_VSDOT(DisasContext * s,arg_VSDOT * a)268f0ad96cbSRichard Henderson static bool trans_VSDOT(DisasContext *s, arg_VSDOT *a)
26932da0e33SPeter Maydell {
27032da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
27132da0e33SPeter Maydell         return false;
27232da0e33SPeter Maydell     }
2735a46304cSRichard Henderson     return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0,
274f0ad96cbSRichard Henderson                         gen_helper_gvec_sdot_b);
275f0ad96cbSRichard Henderson }
276f0ad96cbSRichard Henderson 
trans_VUDOT(DisasContext * s,arg_VUDOT * a)277f0ad96cbSRichard Henderson static bool trans_VUDOT(DisasContext *s, arg_VUDOT *a)
278f0ad96cbSRichard Henderson {
279f0ad96cbSRichard Henderson     if (!dc_isar_feature(aa32_dp, s)) {
280f0ad96cbSRichard Henderson         return false;
281f0ad96cbSRichard Henderson     }
282f0ad96cbSRichard Henderson     return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0,
283f0ad96cbSRichard Henderson                         gen_helper_gvec_udot_b);
28432da0e33SPeter Maydell }
2859a107e7bSPeter Maydell 
trans_VUSDOT(DisasContext * s,arg_VUSDOT * a)28651879c67SRichard Henderson static bool trans_VUSDOT(DisasContext *s, arg_VUSDOT *a)
28751879c67SRichard Henderson {
28851879c67SRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
28951879c67SRichard Henderson         return false;
29051879c67SRichard Henderson     }
29151879c67SRichard Henderson     return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0,
29251879c67SRichard Henderson                         gen_helper_gvec_usdot_b);
29351879c67SRichard Henderson }
29451879c67SRichard Henderson 
trans_VDOT_b16(DisasContext * s,arg_VDOT_b16 * a)295cb8657f7SRichard Henderson static bool trans_VDOT_b16(DisasContext *s, arg_VDOT_b16 *a)
296cb8657f7SRichard Henderson {
297cb8657f7SRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
298cb8657f7SRichard Henderson         return false;
299cb8657f7SRichard Henderson     }
30075a6784dSPeter Maydell     return do_neon_ddda_env(s, a->q * 7, a->vd, a->vn, a->vm, 0,
301cb8657f7SRichard Henderson                             gen_helper_gvec_bfdot);
302cb8657f7SRichard Henderson }
303cb8657f7SRichard Henderson 
trans_VFML(DisasContext * s,arg_VFML * a)3049a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
3059a107e7bSPeter Maydell {
3069a107e7bSPeter Maydell     int opr_sz;
3079a107e7bSPeter Maydell 
3089a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
3099a107e7bSPeter Maydell         return false;
3109a107e7bSPeter Maydell     }
3119a107e7bSPeter Maydell 
3129a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3139a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3149a107e7bSPeter Maydell         (a->vd & 0x10)) {
3159a107e7bSPeter Maydell         return false;
3169a107e7bSPeter Maydell     }
3179a107e7bSPeter Maydell 
3189a107e7bSPeter Maydell     if (a->vd & a->q) {
3199a107e7bSPeter Maydell         return false;
3209a107e7bSPeter Maydell     }
3219a107e7bSPeter Maydell 
3229a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
3239a107e7bSPeter Maydell         return true;
3249a107e7bSPeter Maydell     }
3259a107e7bSPeter Maydell 
3269a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
3279a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
3289a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
3299a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
330ad75a51eSRichard Henderson                        tcg_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
3319a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
3329a107e7bSPeter Maydell     return true;
3339a107e7bSPeter Maydell }
3347e1b5d61SPeter Maydell 
trans_VCMLA_scalar(DisasContext * s,arg_VCMLA_scalar * a)3357e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
3367e1b5d61SPeter Maydell {
337505fce50SRichard Henderson     int data = (a->index << 2) | a->rot;
3387e1b5d61SPeter Maydell 
3397e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
3407e1b5d61SPeter Maydell         return false;
3417e1b5d61SPeter Maydell     }
342505fce50SRichard Henderson     if (a->size == MO_16) {
343505fce50SRichard Henderson         if (!dc_isar_feature(aa32_fp16_arith, s)) {
3447e1b5d61SPeter Maydell             return false;
3457e1b5d61SPeter Maydell         }
346505fce50SRichard Henderson         return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data,
347505fce50SRichard Henderson                                  FPST_STD_F16, gen_helper_gvec_fcmlah_idx);
3487e1b5d61SPeter Maydell     }
349505fce50SRichard Henderson     return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data,
350505fce50SRichard Henderson                              FPST_STD, gen_helper_gvec_fcmlas_idx);
3517e1b5d61SPeter Maydell }
35235f5d4d1SPeter Maydell 
trans_VSDOT_scalar(DisasContext * s,arg_VSDOT_scalar * a)353f0ad96cbSRichard Henderson static bool trans_VSDOT_scalar(DisasContext *s, arg_VSDOT_scalar *a)
35435f5d4d1SPeter Maydell {
35535f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
35635f5d4d1SPeter Maydell         return false;
35735f5d4d1SPeter Maydell     }
3585a46304cSRichard Henderson     return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
359f0ad96cbSRichard Henderson                         gen_helper_gvec_sdot_idx_b);
360f0ad96cbSRichard Henderson }
361f0ad96cbSRichard Henderson 
trans_VUDOT_scalar(DisasContext * s,arg_VUDOT_scalar * a)362f0ad96cbSRichard Henderson static bool trans_VUDOT_scalar(DisasContext *s, arg_VUDOT_scalar *a)
363f0ad96cbSRichard Henderson {
364f0ad96cbSRichard Henderson     if (!dc_isar_feature(aa32_dp, s)) {
365f0ad96cbSRichard Henderson         return false;
366f0ad96cbSRichard Henderson     }
367f0ad96cbSRichard Henderson     return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
368f0ad96cbSRichard Henderson                         gen_helper_gvec_udot_idx_b);
36935f5d4d1SPeter Maydell }
370d27e82f7SPeter Maydell 
trans_VUSDOT_scalar(DisasContext * s,arg_VUSDOT_scalar * a)37151879c67SRichard Henderson static bool trans_VUSDOT_scalar(DisasContext *s, arg_VUSDOT_scalar *a)
37251879c67SRichard Henderson {
37351879c67SRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
37451879c67SRichard Henderson         return false;
37551879c67SRichard Henderson     }
37651879c67SRichard Henderson     return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
37751879c67SRichard Henderson                         gen_helper_gvec_usdot_idx_b);
37851879c67SRichard Henderson }
37951879c67SRichard Henderson 
trans_VSUDOT_scalar(DisasContext * s,arg_VSUDOT_scalar * a)38051879c67SRichard Henderson static bool trans_VSUDOT_scalar(DisasContext *s, arg_VSUDOT_scalar *a)
38151879c67SRichard Henderson {
38251879c67SRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
38351879c67SRichard Henderson         return false;
38451879c67SRichard Henderson     }
38551879c67SRichard Henderson     return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
38651879c67SRichard Henderson                         gen_helper_gvec_sudot_idx_b);
38751879c67SRichard Henderson }
38851879c67SRichard Henderson 
trans_VDOT_b16_scal(DisasContext * s,arg_VDOT_b16_scal * a)38983914478SRichard Henderson static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a)
39083914478SRichard Henderson {
39183914478SRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
39283914478SRichard Henderson         return false;
39383914478SRichard Henderson     }
394c8d644b9SPeter Maydell     return do_neon_ddda_env(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
39583914478SRichard Henderson                             gen_helper_gvec_bfdot_idx);
39683914478SRichard Henderson }
39783914478SRichard Henderson 
trans_VFML_scalar(DisasContext * s,arg_VFML_scalar * a)398d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
399d27e82f7SPeter Maydell {
400d27e82f7SPeter Maydell     int opr_sz;
401d27e82f7SPeter Maydell 
402d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
403d27e82f7SPeter Maydell         return false;
404d27e82f7SPeter Maydell     }
405d27e82f7SPeter Maydell 
406d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
407d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
408d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
409d27e82f7SPeter Maydell         return false;
410d27e82f7SPeter Maydell     }
411d27e82f7SPeter Maydell 
412d27e82f7SPeter Maydell     if (a->vd & a->q) {
413d27e82f7SPeter Maydell         return false;
414d27e82f7SPeter Maydell     }
415d27e82f7SPeter Maydell 
416d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
417d27e82f7SPeter Maydell         return true;
418d27e82f7SPeter Maydell     }
419d27e82f7SPeter Maydell 
420d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
421d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
422d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
423d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
424ad75a51eSRichard Henderson                        tcg_env, opr_sz, opr_sz,
425d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
426d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
427d27e82f7SPeter Maydell     return true;
428d27e82f7SPeter Maydell }
429a27b4630SPeter Maydell 
430a27b4630SPeter Maydell static struct {
431a27b4630SPeter Maydell     int nregs;
432a27b4630SPeter Maydell     int interleave;
433a27b4630SPeter Maydell     int spacing;
434a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
435a27b4630SPeter Maydell     {1, 4, 1},
436a27b4630SPeter Maydell     {1, 4, 2},
437a27b4630SPeter Maydell     {4, 1, 1},
438a27b4630SPeter Maydell     {2, 2, 2},
439a27b4630SPeter Maydell     {1, 3, 1},
440a27b4630SPeter Maydell     {1, 3, 2},
441a27b4630SPeter Maydell     {3, 1, 1},
442a27b4630SPeter Maydell     {1, 1, 1},
443a27b4630SPeter Maydell     {1, 2, 1},
444a27b4630SPeter Maydell     {1, 2, 2},
445a27b4630SPeter Maydell     {2, 1, 1}
446a27b4630SPeter Maydell };
447a27b4630SPeter Maydell 
gen_neon_ldst_base_update(DisasContext * s,int rm,int rn,int stride)448a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
449a27b4630SPeter Maydell                                       int stride)
450a27b4630SPeter Maydell {
451a27b4630SPeter Maydell     if (rm != 15) {
452a27b4630SPeter Maydell         TCGv_i32 base;
453a27b4630SPeter Maydell 
454a27b4630SPeter Maydell         base = load_reg(s, rn);
455a27b4630SPeter Maydell         if (rm == 13) {
456a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
457a27b4630SPeter Maydell         } else {
458a27b4630SPeter Maydell             TCGv_i32 index;
459a27b4630SPeter Maydell             index = load_reg(s, rm);
460a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
461a27b4630SPeter Maydell         }
462a27b4630SPeter Maydell         store_reg(s, rn, base);
463a27b4630SPeter Maydell     }
464a27b4630SPeter Maydell }
465a27b4630SPeter Maydell 
trans_VLDST_multiple(DisasContext * s,arg_VLDST_multiple * a)466a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
467a27b4630SPeter Maydell {
468a27b4630SPeter Maydell     /* Neon load/store multiple structures */
469a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
4707c68c196SRichard Henderson     MemOp mop, align, endian;
471a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
472a27b4630SPeter Maydell     int size = a->size;
473a27b4630SPeter Maydell     TCGv_i64 tmp64;
474d9b47e97SRichard Henderson     TCGv_i32 addr;
475a27b4630SPeter Maydell 
476a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
477a27b4630SPeter Maydell         return false;
478a27b4630SPeter Maydell     }
479a27b4630SPeter Maydell 
480a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
481a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
482a27b4630SPeter Maydell         return false;
483a27b4630SPeter Maydell     }
484a27b4630SPeter Maydell     if (a->itype > 10) {
485a27b4630SPeter Maydell         return false;
486a27b4630SPeter Maydell     }
487a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
488a27b4630SPeter Maydell     switch (a->itype & 0xc) {
489a27b4630SPeter Maydell     case 4:
490a27b4630SPeter Maydell         if (a->align >= 2) {
491a27b4630SPeter Maydell             return false;
492a27b4630SPeter Maydell         }
493a27b4630SPeter Maydell         break;
494a27b4630SPeter Maydell     case 8:
495a27b4630SPeter Maydell         if (a->align == 3) {
496a27b4630SPeter Maydell             return false;
497a27b4630SPeter Maydell         }
498a27b4630SPeter Maydell         break;
499a27b4630SPeter Maydell     default:
500a27b4630SPeter Maydell         break;
501a27b4630SPeter Maydell     }
502a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
503a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
504a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
505a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
506a27b4630SPeter Maydell         return false;
507a27b4630SPeter Maydell     }
508a27b4630SPeter Maydell 
509a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
510a27b4630SPeter Maydell         return true;
511a27b4630SPeter Maydell     }
512a27b4630SPeter Maydell 
513a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
5147c68c196SRichard Henderson     endian = s->be_data;
515a27b4630SPeter Maydell     if (size == 0) {
516a27b4630SPeter Maydell         endian = MO_LE;
517a27b4630SPeter Maydell     }
5187c68c196SRichard Henderson 
5197c68c196SRichard Henderson     /* Enforce alignment requested by the instruction */
5207c68c196SRichard Henderson     if (a->align) {
5217c68c196SRichard Henderson         align = pow2_align(a->align + 2); /* 4 ** a->align */
5227c68c196SRichard Henderson     } else {
5237c68c196SRichard Henderson         align = s->align_mem ? MO_ALIGN : 0;
5247c68c196SRichard Henderson     }
5257c68c196SRichard Henderson 
526a27b4630SPeter Maydell     /*
527a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
528a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
529a27b4630SPeter Maydell      */
530a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
5317c68c196SRichard Henderson         /* Retain any natural alignment. */
5327c68c196SRichard Henderson         if (align == MO_ALIGN) {
5337c68c196SRichard Henderson             align = pow2_align(size);
5347c68c196SRichard Henderson         }
535a27b4630SPeter Maydell         size = 3;
536a27b4630SPeter Maydell     }
5377c68c196SRichard Henderson 
538a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
539a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
540a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
5417c68c196SRichard Henderson 
5427c68c196SRichard Henderson     mop = endian | size | align;
543a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
544a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
545a27b4630SPeter Maydell             int xs;
546a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
547a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
548a27b4630SPeter Maydell 
549a27b4630SPeter Maydell                 if (a->l) {
5507c68c196SRichard Henderson                     gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop);
551a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
552a27b4630SPeter Maydell                 } else {
553a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
5547c68c196SRichard Henderson                     gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop);
555a27b4630SPeter Maydell                 }
556d9b47e97SRichard Henderson                 tcg_gen_addi_i32(addr, addr, 1 << size);
5577c68c196SRichard Henderson 
5587c68c196SRichard Henderson                 /* Subsequent memory operations inherit alignment */
5597c68c196SRichard Henderson                 mop &= ~MO_AMASK;
560a27b4630SPeter Maydell             }
561a27b4630SPeter Maydell         }
562a27b4630SPeter Maydell     }
563a27b4630SPeter Maydell 
564a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
565a27b4630SPeter Maydell     return true;
566a27b4630SPeter Maydell }
5673698747cSPeter Maydell 
trans_VLD_all_lanes(DisasContext * s,arg_VLD_all_lanes * a)5683698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
5693698747cSPeter Maydell {
5703698747cSPeter Maydell     /* Neon load single structure to all lanes */
5713698747cSPeter Maydell     int reg, stride, vec_size;
5723698747cSPeter Maydell     int vd = a->vd;
5733698747cSPeter Maydell     int size = a->size;
5743698747cSPeter Maydell     int nregs = a->n + 1;
5753698747cSPeter Maydell     TCGv_i32 addr, tmp;
576a8502b37SRichard Henderson     MemOp mop, align;
5773698747cSPeter Maydell 
5783698747cSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
5793698747cSPeter Maydell         return false;
5803698747cSPeter Maydell     }
5813698747cSPeter Maydell 
5823698747cSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
5833698747cSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
5843698747cSPeter Maydell         return false;
5853698747cSPeter Maydell     }
5863698747cSPeter Maydell 
587a8502b37SRichard Henderson     align = 0;
5883698747cSPeter Maydell     if (size == 3) {
5893698747cSPeter Maydell         if (nregs != 4 || a->a == 0) {
5903698747cSPeter Maydell             return false;
5913698747cSPeter Maydell         }
5923698747cSPeter Maydell         /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */
593a8502b37SRichard Henderson         size = MO_32;
594a8502b37SRichard Henderson         align = MO_ALIGN_16;
595a8502b37SRichard Henderson     } else if (a->a) {
596a8502b37SRichard Henderson         switch (nregs) {
597a8502b37SRichard Henderson         case 1:
598a8502b37SRichard Henderson             if (size == 0) {
5993698747cSPeter Maydell                 return false;
6003698747cSPeter Maydell             }
601a8502b37SRichard Henderson             align = MO_ALIGN;
602a8502b37SRichard Henderson             break;
603a8502b37SRichard Henderson         case 2:
604a8502b37SRichard Henderson             align = pow2_align(size + 1);
605a8502b37SRichard Henderson             break;
606a8502b37SRichard Henderson         case 3:
6073698747cSPeter Maydell             return false;
608a8502b37SRichard Henderson         case 4:
6093a661024SClément Chigot             if (size == 2) {
6103a661024SClément Chigot                 align = pow2_align(3);
6113a661024SClément Chigot             } else {
612a8502b37SRichard Henderson                 align = pow2_align(size + 2);
6133a661024SClément Chigot             }
614a8502b37SRichard Henderson             break;
615a8502b37SRichard Henderson         default:
616a8502b37SRichard Henderson             g_assert_not_reached();
617a8502b37SRichard Henderson         }
6183698747cSPeter Maydell     }
6193698747cSPeter Maydell 
6203698747cSPeter Maydell     if (!vfp_access_check(s)) {
6213698747cSPeter Maydell         return true;
6223698747cSPeter Maydell     }
6233698747cSPeter Maydell 
6243698747cSPeter Maydell     /*
6253698747cSPeter Maydell      * VLD1 to all lanes: T bit indicates how many Dregs to write.
6263698747cSPeter Maydell      * VLD2/3/4 to all lanes: T bit indicates register stride.
6273698747cSPeter Maydell      */
6283698747cSPeter Maydell     stride = a->t ? 2 : 1;
6293698747cSPeter Maydell     vec_size = nregs == 1 ? stride * 8 : 8;
630a8502b37SRichard Henderson     mop = size | align;
6313698747cSPeter Maydell     tmp = tcg_temp_new_i32();
6323698747cSPeter Maydell     addr = tcg_temp_new_i32();
6333698747cSPeter Maydell     load_reg_var(s, addr, a->rn);
6343698747cSPeter Maydell     for (reg = 0; reg < nregs; reg++) {
635a8502b37SRichard Henderson         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop);
6363698747cSPeter Maydell         if ((vd & 1) && vec_size == 16) {
6373698747cSPeter Maydell             /*
6383698747cSPeter Maydell              * We cannot write 16 bytes at once because the
6393698747cSPeter Maydell              * destination is unaligned.
6403698747cSPeter Maydell              */
641015ee81aSRichard Henderson             tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd),
6423698747cSPeter Maydell                                  8, 8, tmp);
643015ee81aSRichard Henderson             tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1),
644015ee81aSRichard Henderson                              neon_full_reg_offset(vd), 8, 8);
6453698747cSPeter Maydell         } else {
646015ee81aSRichard Henderson             tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd),
6473698747cSPeter Maydell                                  vec_size, vec_size, tmp);
6483698747cSPeter Maydell         }
6493698747cSPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << size);
6503698747cSPeter Maydell         vd += stride;
651a8502b37SRichard Henderson 
652a8502b37SRichard Henderson         /* Subsequent memory operations inherit alignment */
653a8502b37SRichard Henderson         mop &= ~MO_AMASK;
6543698747cSPeter Maydell     }
6553698747cSPeter Maydell 
6563698747cSPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs);
6573698747cSPeter Maydell 
6583698747cSPeter Maydell     return true;
6593698747cSPeter Maydell }
660123ce4e3SPeter Maydell 
trans_VLDST_single(DisasContext * s,arg_VLDST_single * a)661123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
662123ce4e3SPeter Maydell {
663123ce4e3SPeter Maydell     /* Neon load/store single structure to one lane */
664123ce4e3SPeter Maydell     int reg;
665123ce4e3SPeter Maydell     int nregs = a->n + 1;
666123ce4e3SPeter Maydell     int vd = a->vd;
667123ce4e3SPeter Maydell     TCGv_i32 addr, tmp;
66888976ff0SRichard Henderson     MemOp mop;
669123ce4e3SPeter Maydell 
670123ce4e3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
671123ce4e3SPeter Maydell         return false;
672123ce4e3SPeter Maydell     }
673123ce4e3SPeter Maydell 
674123ce4e3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
675123ce4e3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
676123ce4e3SPeter Maydell         return false;
677123ce4e3SPeter Maydell     }
678123ce4e3SPeter Maydell 
679123ce4e3SPeter Maydell     /* Catch the UNDEF cases. This is unavoidably a bit messy. */
680123ce4e3SPeter Maydell     switch (nregs) {
681123ce4e3SPeter Maydell     case 1:
682c64ee036SPeter Maydell         if (a->stride != 1) {
683c64ee036SPeter Maydell             return false;
684c64ee036SPeter Maydell         }
685123ce4e3SPeter Maydell         if (((a->align & (1 << a->size)) != 0) ||
686a736cbc3SRichard Henderson             (a->size == 2 && (a->align == 1 || a->align == 2))) {
687123ce4e3SPeter Maydell             return false;
688123ce4e3SPeter Maydell         }
689123ce4e3SPeter Maydell         break;
690123ce4e3SPeter Maydell     case 2:
691123ce4e3SPeter Maydell         if (a->size == 2 && (a->align & 2) != 0) {
692123ce4e3SPeter Maydell             return false;
693123ce4e3SPeter Maydell         }
694123ce4e3SPeter Maydell         break;
69541c5a0f7SPeter Maydell     case 3:
69641c5a0f7SPeter Maydell         if (a->align != 0) {
69741c5a0f7SPeter Maydell             return false;
69841c5a0f7SPeter Maydell         }
69941c5a0f7SPeter Maydell         break;
700123ce4e3SPeter Maydell     case 4:
701a736cbc3SRichard Henderson         if (a->size == 2 && a->align == 3) {
702123ce4e3SPeter Maydell             return false;
703123ce4e3SPeter Maydell         }
704123ce4e3SPeter Maydell         break;
705123ce4e3SPeter Maydell     default:
706d385a605SRichard Henderson         g_assert_not_reached();
707123ce4e3SPeter Maydell     }
708123ce4e3SPeter Maydell     if ((vd + a->stride * (nregs - 1)) > 31) {
709123ce4e3SPeter Maydell         /*
710123ce4e3SPeter Maydell          * Attempts to write off the end of the register file are
711123ce4e3SPeter Maydell          * UNPREDICTABLE; we choose to UNDEF because otherwise we would
712123ce4e3SPeter Maydell          * access off the end of the array that holds the register data.
713123ce4e3SPeter Maydell          */
714123ce4e3SPeter Maydell         return false;
715123ce4e3SPeter Maydell     }
716123ce4e3SPeter Maydell 
717123ce4e3SPeter Maydell     if (!vfp_access_check(s)) {
718123ce4e3SPeter Maydell         return true;
719123ce4e3SPeter Maydell     }
720123ce4e3SPeter Maydell 
72188976ff0SRichard Henderson     /* Pick up SCTLR settings */
72288976ff0SRichard Henderson     mop = finalize_memop(s, a->size);
72388976ff0SRichard Henderson 
72488976ff0SRichard Henderson     if (a->align) {
72588976ff0SRichard Henderson         MemOp align_op;
72688976ff0SRichard Henderson 
72788976ff0SRichard Henderson         switch (nregs) {
72888976ff0SRichard Henderson         case 1:
72988976ff0SRichard Henderson             /* For VLD1, use natural alignment. */
73088976ff0SRichard Henderson             align_op = MO_ALIGN;
73188976ff0SRichard Henderson             break;
73288976ff0SRichard Henderson         case 2:
73388976ff0SRichard Henderson             /* For VLD2, use double alignment. */
73488976ff0SRichard Henderson             align_op = pow2_align(a->size + 1);
73588976ff0SRichard Henderson             break;
73688976ff0SRichard Henderson         case 4:
73788976ff0SRichard Henderson             if (a->size == MO_32) {
73888976ff0SRichard Henderson                 /*
73988976ff0SRichard Henderson                  * For VLD4.32, align = 1 is double alignment, align = 2 is
74088976ff0SRichard Henderson                  * quad alignment; align = 3 is rejected above.
74188976ff0SRichard Henderson                  */
74288976ff0SRichard Henderson                 align_op = pow2_align(a->size + a->align);
74388976ff0SRichard Henderson             } else {
74488976ff0SRichard Henderson                 /* For VLD4.8 and VLD.16, we want quad alignment. */
74588976ff0SRichard Henderson                 align_op = pow2_align(a->size + 2);
74688976ff0SRichard Henderson             }
74788976ff0SRichard Henderson             break;
74888976ff0SRichard Henderson         default:
74988976ff0SRichard Henderson             /* For VLD3, the alignment field is zero and rejected above. */
75088976ff0SRichard Henderson             g_assert_not_reached();
75188976ff0SRichard Henderson         }
75288976ff0SRichard Henderson 
75388976ff0SRichard Henderson         mop = (mop & ~MO_AMASK) | align_op;
75488976ff0SRichard Henderson     }
75588976ff0SRichard Henderson 
756123ce4e3SPeter Maydell     tmp = tcg_temp_new_i32();
757123ce4e3SPeter Maydell     addr = tcg_temp_new_i32();
758123ce4e3SPeter Maydell     load_reg_var(s, addr, a->rn);
75988976ff0SRichard Henderson 
760123ce4e3SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
761123ce4e3SPeter Maydell         if (a->l) {
76288976ff0SRichard Henderson             gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop);
763123ce4e3SPeter Maydell             neon_store_element(vd, a->reg_idx, a->size, tmp);
764123ce4e3SPeter Maydell         } else { /* Store */
765123ce4e3SPeter Maydell             neon_load_element(tmp, vd, a->reg_idx, a->size);
76688976ff0SRichard Henderson             gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop);
767123ce4e3SPeter Maydell         }
768123ce4e3SPeter Maydell         vd += a->stride;
769123ce4e3SPeter Maydell         tcg_gen_addi_i32(addr, addr, 1 << a->size);
77088976ff0SRichard Henderson 
77188976ff0SRichard Henderson         /* Subsequent memory operations inherit alignment */
77288976ff0SRichard Henderson         mop &= ~MO_AMASK;
773123ce4e3SPeter Maydell     }
774123ce4e3SPeter Maydell 
775123ce4e3SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
776123ce4e3SPeter Maydell 
777123ce4e3SPeter Maydell     return true;
778123ce4e3SPeter Maydell }
779a4e143acSPeter Maydell 
do_3same(DisasContext * s,arg_3same * a,GVecGen3Fn fn)780a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn)
781a4e143acSPeter Maydell {
782a4e143acSPeter Maydell     int vec_size = a->q ? 16 : 8;
783015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
784015ee81aSRichard Henderson     int rn_ofs = neon_full_reg_offset(a->vn);
785015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
786a4e143acSPeter Maydell 
787a4e143acSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
788a4e143acSPeter Maydell         return false;
789a4e143acSPeter Maydell     }
790a4e143acSPeter Maydell 
791a4e143acSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
792a4e143acSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
793a4e143acSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
794a4e143acSPeter Maydell         return false;
795a4e143acSPeter Maydell     }
796a4e143acSPeter Maydell 
797a4e143acSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
798a4e143acSPeter Maydell         return false;
799a4e143acSPeter Maydell     }
800a4e143acSPeter Maydell 
801a4e143acSPeter Maydell     if (!vfp_access_check(s)) {
802a4e143acSPeter Maydell         return true;
803a4e143acSPeter Maydell     }
804a4e143acSPeter Maydell 
805a4e143acSPeter Maydell     fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size);
806a4e143acSPeter Maydell     return true;
807a4e143acSPeter Maydell }
808a4e143acSPeter Maydell 
809a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC)                                            \
810a4e143acSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
811a4e143acSPeter Maydell     {                                                                   \
812a4e143acSPeter Maydell         return do_3same(s, a, FUNC);                                    \
813a4e143acSPeter Maydell     }
814a4e143acSPeter Maydell 
DO_3SAME(VADD,tcg_gen_gvec_add)815a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add)
816a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub)
81735a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and)
81835a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc)
81935a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or)
82035a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc)
82135a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor)
8228161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl)
8238161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl)
824c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc)
825c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc)
826c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc)
827c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc)
828940392c8SRichard Henderson DO_3SAME(VRSHL_S, gen_gvec_srshl)
829940392c8SRichard Henderson DO_3SAME(VRSHL_U, gen_gvec_urshl)
830e72a6878SRichard Henderson DO_3SAME(VQSHL_S, gen_neon_sqshl)
831e72a6878SRichard Henderson DO_3SAME(VQSHL_U, gen_neon_uqshl)
832cef9d54fSRichard Henderson DO_3SAME(VQRSHL_S, gen_neon_sqrshl)
833cef9d54fSRichard Henderson DO_3SAME(VQRSHL_U, gen_neon_uqrshl)
83435a548edSPeter Maydell 
83535a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */
83635a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3)                               \
83735a548edSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
83835a548edSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
83935a548edSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
84035a548edSPeter Maydell     {                                                                   \
84135a548edSPeter Maydell         tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz);    \
84235a548edSPeter Maydell     }                                                                   \
84335a548edSPeter Maydell     DO_3SAME(INSN, gen_##INSN##_3s)
84435a548edSPeter Maydell 
84535a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs)
84635a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs)
84735a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs)
84836b59310SPeter Maydell 
84936b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC)                                    \
85036b59310SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
85136b59310SPeter Maydell     {                                                                   \
85236b59310SPeter Maydell         if (a->size == 3) {                                             \
85336b59310SPeter Maydell             return false;                                               \
85436b59310SPeter Maydell         }                                                               \
85536b59310SPeter Maydell         return do_3same(s, a, FUNC);                                    \
85636b59310SPeter Maydell     }
85736b59310SPeter Maydell 
85836b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax)
85936b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax)
86036b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin)
86136b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin)
8620de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul)
86327106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla)
86427106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls)
8658161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst)
8667715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd)
8677715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba)
8687715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd)
8697715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba)
870a11e54edSRichard Henderson DO_3SAME_NO_SZ_3(VPADD, gen_gvec_addp)
871a9240f48SRichard Henderson DO_3SAME_NO_SZ_3(VPMAX_S, gen_gvec_smaxp)
872a9240f48SRichard Henderson DO_3SAME_NO_SZ_3(VPMIN_S, gen_gvec_sminp)
873a9240f48SRichard Henderson DO_3SAME_NO_SZ_3(VPMAX_U, gen_gvec_umaxp)
874a9240f48SRichard Henderson DO_3SAME_NO_SZ_3(VPMIN_U, gen_gvec_uminp)
875203aca91SRichard Henderson DO_3SAME_NO_SZ_3(VHADD_S, gen_gvec_shadd)
876203aca91SRichard Henderson DO_3SAME_NO_SZ_3(VHADD_U, gen_gvec_uhadd)
87734c0d865SRichard Henderson DO_3SAME_NO_SZ_3(VHSUB_S, gen_gvec_shsub)
87834c0d865SRichard Henderson DO_3SAME_NO_SZ_3(VHSUB_U, gen_gvec_uhsub)
8798989b95eSRichard Henderson DO_3SAME_NO_SZ_3(VRHADD_S, gen_gvec_srhadd)
8808989b95eSRichard Henderson DO_3SAME_NO_SZ_3(VRHADD_U, gen_gvec_urhadd)
88102bd0cdbSPeter Maydell 
88202bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND)                                        \
88302bd0cdbSPeter Maydell     static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs,         \
88402bd0cdbSPeter Maydell                                 uint32_t rn_ofs, uint32_t rm_ofs,       \
88502bd0cdbSPeter Maydell                                 uint32_t oprsz, uint32_t maxsz)         \
88602bd0cdbSPeter Maydell     {                                                                   \
88702bd0cdbSPeter Maydell         tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \
88802bd0cdbSPeter Maydell     }                                                                   \
88902bd0cdbSPeter Maydell     DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s)
89002bd0cdbSPeter Maydell 
89102bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT)
89202bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU)
89302bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE)
89402bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU)
89502bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ)
89602bd0cdbSPeter Maydell 
897effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC)                                        \
898effa992fSRichard Henderson     static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,  \
899effa992fSRichard Henderson                          uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz)  \
900effa992fSRichard Henderson     {                                                                      \
901effa992fSRichard Henderson         tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \
9020de34fd4SPeter Maydell     }
9030de34fd4SPeter Maydell 
904effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b)
905effa992fSRichard Henderson 
9060de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a)
9070de34fd4SPeter Maydell {
9080de34fd4SPeter Maydell     if (a->size != 0) {
9090de34fd4SPeter Maydell         return false;
9100de34fd4SPeter Maydell     }
9110de34fd4SPeter Maydell     return do_3same(s, a, gen_VMUL_p_3s);
9120de34fd4SPeter Maydell }
913a0635695SPeter Maydell 
914a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC)                                         \
915a0635695SPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
916a0635695SPeter Maydell     {                                                                   \
917a0635695SPeter Maydell         if (!dc_isar_feature(aa32_rdm, s)) {                            \
918a0635695SPeter Maydell             return false;                                               \
919a0635695SPeter Maydell         }                                                               \
920a0635695SPeter Maydell         if (a->size != 1 && a->size != 2) {                             \
921a0635695SPeter Maydell             return false;                                               \
922a0635695SPeter Maydell         }                                                               \
923a0635695SPeter Maydell         return do_3same(s, a, FUNC);                                    \
924a0635695SPeter Maydell     }
925a0635695SPeter Maydell 
DO_VQRDMLAH(VQRDMLAH,gen_gvec_sqrdmlah_qc)926a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc)
927a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc)
92821290edfSPeter Maydell 
929afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC)                                             \
930afc8b7d3SRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
931afc8b7d3SRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
932afc8b7d3SRichard Henderson     {                                                                   \
933afc8b7d3SRichard Henderson         if (!dc_isar_feature(aa32_sha1, s)) {                           \
934afc8b7d3SRichard Henderson             return false;                                               \
935afc8b7d3SRichard Henderson         }                                                               \
936afc8b7d3SRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
93721290edfSPeter Maydell     }
93821290edfSPeter Maydell 
939afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c)
940afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p)
941afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m)
942afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0)
94321290edfSPeter Maydell 
944effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC)                                             \
945effa992fSRichard Henderson     WRAP_OOL_FN(gen_##NAME##_3s, FUNC)                                  \
946effa992fSRichard Henderson     static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a)        \
947effa992fSRichard Henderson     {                                                                   \
948effa992fSRichard Henderson         if (!dc_isar_feature(aa32_sha2, s)) {                           \
949effa992fSRichard Henderson             return false;                                               \
950effa992fSRichard Henderson         }                                                               \
951effa992fSRichard Henderson         return do_3same(s, a, gen_##NAME##_3s);                         \
95221290edfSPeter Maydell     }
95321290edfSPeter Maydell 
954effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h)
955effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2)
956effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1)
95735d4352fSPeter Maydell 
9586812dfdcSPeter Maydell /*
959ad75a51eSRichard Henderson  * Some helper functions need to be passed the tcg_env. In order
9606812dfdcSPeter Maydell  * to use those with the gvec APIs like tcg_gen_gvec_3() we need
9616812dfdcSPeter Maydell  * to create wrapper functions whose prototype is a NeonGenTwoOpFn()
9626812dfdcSPeter Maydell  * and which call a NeonGenTwoOpEnvFn().
9636812dfdcSPeter Maydell  */
9646812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC)                                     \
9656812dfdcSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m)            \
9666812dfdcSPeter Maydell     {                                                                   \
967ad75a51eSRichard Henderson         FUNC(d, tcg_env, n, m);                                         \
9686812dfdcSPeter Maydell     }
9696812dfdcSPeter Maydell 
9707ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC)                                    \
9717ecc28bcSPeter Maydell     static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a)        \
9728f81dcedSRichard Henderson     { return a->size >= 1 && a->size <= 2 && do_3same(s, a, FUNC); }
9737ecc28bcSPeter Maydell 
9748f81dcedSRichard Henderson DO_3SAME_VQDMULH(VQDMULH, gen_gvec_sqdmulh_qc)
9758f81dcedSRichard Henderson DO_3SAME_VQDMULH(VQRDMULH, gen_gvec_sqrdmulh_qc)
976a26a352bSPeter Maydell 
977e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC)                              \
978e4a6d4a6SPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
979a26a352bSPeter Maydell                          uint32_t rn_ofs, uint32_t rm_ofs,              \
980a26a352bSPeter Maydell                          uint32_t oprsz, uint32_t maxsz)                \
981a26a352bSPeter Maydell     {                                                                   \
982e4a6d4a6SPeter Maydell         TCGv_ptr fpst = fpstatus_ptr(FPST);                             \
983a26a352bSPeter Maydell         tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst,                \
984a26a352bSPeter Maydell                            oprsz, maxsz, 0, FUNC);                      \
985e4a6d4a6SPeter Maydell     }
986e4a6d4a6SPeter Maydell 
987e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC)                                 \
988e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC)                 \
989e4a6d4a6SPeter Maydell     WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC)             \
990a26a352bSPeter Maydell     static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a)     \
991a26a352bSPeter Maydell     {                                                                   \
9926cf0f240SPeter Maydell         if (a->size == MO_16) {                                         \
993e4a6d4a6SPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
994a26a352bSPeter Maydell                 return false;                                           \
995a26a352bSPeter Maydell             }                                                           \
996e4a6d4a6SPeter Maydell             return do_3same(s, a, gen_##INSN##_fp16_3s);                \
997e4a6d4a6SPeter Maydell         }                                                               \
998e4a6d4a6SPeter Maydell         return do_3same(s, a, gen_##INSN##_fp32_3s);                    \
999a26a352bSPeter Maydell     }
1000a26a352bSPeter Maydell 
1001a26a352bSPeter Maydell 
1002e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h)
1003e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h)
1004e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h)
1005e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h)
1006ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h)
1007ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h)
1008ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h)
1009bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h)
1010bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h)
1011e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h)
1012e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h)
1013e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h)
1014e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h)
1015cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h)
1016cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h)
1017ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h)
101840fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h)
1019c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPADD, gen_helper_gvec_faddp_s, gen_helper_gvec_faddp_h)
1020c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPMAX, gen_helper_gvec_fmaxp_s, gen_helper_gvec_fmaxp_h)
1021c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPMIN, gen_helper_gvec_fminp_s, gen_helper_gvec_fminp_h)
1022ab978335SPeter Maydell 
1023e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s)
1024e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h)
1025e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s)
1026e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h)
1027e22705bbSPeter Maydell 
1028d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a)
1029d5fdf9e9SPeter Maydell {
1030d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1031d5fdf9e9SPeter Maydell         return false;
1032d5fdf9e9SPeter Maydell     }
1033d5fdf9e9SPeter Maydell 
10346cf0f240SPeter Maydell     if (a->size == MO_16) {
1035e22705bbSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
1036d5fdf9e9SPeter Maydell             return false;
1037d5fdf9e9SPeter Maydell         }
1038e22705bbSPeter Maydell         return do_3same(s, a, gen_VMAXNM_fp16_3s);
1039e22705bbSPeter Maydell     }
1040e22705bbSPeter Maydell     return do_3same(s, a, gen_VMAXNM_fp32_3s);
1041d5fdf9e9SPeter Maydell }
1042d5fdf9e9SPeter Maydell 
trans_VMINNM_fp_3s(DisasContext * s,arg_3same * a)1043d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a)
1044d5fdf9e9SPeter Maydell {
1045d5fdf9e9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
1046d5fdf9e9SPeter Maydell         return false;
1047d5fdf9e9SPeter Maydell     }
1048d5fdf9e9SPeter Maydell 
10496cf0f240SPeter Maydell     if (a->size == MO_16) {
1050e22705bbSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
1051d5fdf9e9SPeter Maydell             return false;
1052d5fdf9e9SPeter Maydell         }
1053e22705bbSPeter Maydell         return do_3same(s, a, gen_VMINNM_fp16_3s);
1054e22705bbSPeter Maydell     }
1055e22705bbSPeter Maydell     return do_3same(s, a, gen_VMINNM_fp32_3s);
1056d5fdf9e9SPeter Maydell }
1057d5fdf9e9SPeter Maydell 
do_vector_2sh(DisasContext * s,arg_2reg_shift * a,GVecGen2iFn * fn)1058d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn)
1059d3c8c736SPeter Maydell {
1060d3c8c736SPeter Maydell     /* Handle a 2-reg-shift insn which can be vectorized. */
1061d3c8c736SPeter Maydell     int vec_size = a->q ? 16 : 8;
1062015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
1063015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
1064d3c8c736SPeter Maydell 
1065d3c8c736SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1066d3c8c736SPeter Maydell         return false;
1067d3c8c736SPeter Maydell     }
1068d3c8c736SPeter Maydell 
1069d3c8c736SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1070d3c8c736SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1071d3c8c736SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1072d3c8c736SPeter Maydell         return false;
1073d3c8c736SPeter Maydell     }
1074d3c8c736SPeter Maydell 
1075d3c8c736SPeter Maydell     if ((a->vm | a->vd) & a->q) {
1076d3c8c736SPeter Maydell         return false;
1077d3c8c736SPeter Maydell     }
1078d3c8c736SPeter Maydell 
1079d3c8c736SPeter Maydell     if (!vfp_access_check(s)) {
1080d3c8c736SPeter Maydell         return true;
1081d3c8c736SPeter Maydell     }
1082d3c8c736SPeter Maydell 
1083d3c8c736SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size);
1084d3c8c736SPeter Maydell     return true;
1085d3c8c736SPeter Maydell }
1086d3c8c736SPeter Maydell 
1087d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC)                                              \
1088d3c8c736SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1089d3c8c736SPeter Maydell     {                                                                   \
1090d3c8c736SPeter Maydell         return do_vector_2sh(s, a, FUNC);                               \
1091d3c8c736SPeter Maydell     }                                                                   \
1092d3c8c736SPeter Maydell 
DO_2SH(VSHL,tcg_gen_gvec_shli)1093d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli)
1094d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli)
1095434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri)
1096434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra)
1097434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra)
1098434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr)
1099434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr)
1100434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra)
1101434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra)
110200bcab5bSRichard Henderson DO_2SH(VSHR_S, gen_gvec_sshr)
110300bcab5bSRichard Henderson DO_2SH(VSHR_U, gen_gvec_ushr)
1104ef2b80ebSRichard Henderson DO_2SH(VQSHLU, gen_neon_sqshlui)
1105ef2b80ebSRichard Henderson DO_2SH(VQSHL_U, gen_neon_uqshli)
1106ef2b80ebSRichard Henderson DO_2SH(VQSHL_S, gen_neon_sqshli)
1107712182d3SPeter Maydell 
1108712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
1109712182d3SPeter Maydell                                 NeonGenTwo64OpFn *shiftfn,
11103e683f0aSRichard Henderson                                 NeonGenOne64OpEnvFn *narrowfn)
1111712182d3SPeter Maydell {
1112712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size == 3 case */
11133e683f0aSRichard Henderson     TCGv_i64 constimm, rm1, rm2, rd;
1114712182d3SPeter Maydell 
1115712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1116712182d3SPeter Maydell         return false;
1117712182d3SPeter Maydell     }
1118712182d3SPeter Maydell 
1119712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1120712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1121712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1122712182d3SPeter Maydell         return false;
1123712182d3SPeter Maydell     }
1124712182d3SPeter Maydell 
1125712182d3SPeter Maydell     if (a->vm & 1) {
1126712182d3SPeter Maydell         return false;
1127712182d3SPeter Maydell     }
1128712182d3SPeter Maydell 
1129712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1130712182d3SPeter Maydell         return true;
1131712182d3SPeter Maydell     }
1132712182d3SPeter Maydell 
1133712182d3SPeter Maydell     /*
1134712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1135712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count.
1136712182d3SPeter Maydell      */
1137d9b47e97SRichard Henderson     constimm = tcg_constant_i64(-a->shift);
1138712182d3SPeter Maydell     rm1 = tcg_temp_new_i64();
1139712182d3SPeter Maydell     rm2 = tcg_temp_new_i64();
11403e683f0aSRichard Henderson     rd = tcg_temp_new_i64();
1141712182d3SPeter Maydell 
1142712182d3SPeter Maydell     /* Load both inputs first to avoid potential overwrite if rm == rd */
11430aa8e700SRichard Henderson     read_neon_element64(rm1, a->vm, 0, MO_64);
11440aa8e700SRichard Henderson     read_neon_element64(rm2, a->vm, 1, MO_64);
1145712182d3SPeter Maydell 
1146712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1147ad75a51eSRichard Henderson     narrowfn(rd, tcg_env, rm1);
11483e683f0aSRichard Henderson     write_neon_element64(rd, a->vd, 0, MO_32);
1149712182d3SPeter Maydell 
1150712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1151ad75a51eSRichard Henderson     narrowfn(rd, tcg_env, rm2);
11523e683f0aSRichard Henderson     write_neon_element64(rd, a->vd, 1, MO_32);
1153712182d3SPeter Maydell 
1154712182d3SPeter Maydell     return true;
1155712182d3SPeter Maydell }
1156712182d3SPeter Maydell 
do_2shift_narrow_32(DisasContext * s,arg_2reg_shift * a,NeonGenTwoOpFn * shiftfn,NeonGenOne64OpEnvFn * narrowfn)1157712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
1158712182d3SPeter Maydell                                 NeonGenTwoOpFn *shiftfn,
11593e683f0aSRichard Henderson                                 NeonGenOne64OpEnvFn *narrowfn)
1160712182d3SPeter Maydell {
1161712182d3SPeter Maydell     /* 2-reg-and-shift narrowing-shift operations, size < 3 case */
1162712182d3SPeter Maydell     TCGv_i32 constimm, rm1, rm2, rm3, rm4;
1163712182d3SPeter Maydell     TCGv_i64 rtmp;
1164712182d3SPeter Maydell     uint32_t imm;
1165712182d3SPeter Maydell 
1166712182d3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1167712182d3SPeter Maydell         return false;
1168712182d3SPeter Maydell     }
1169712182d3SPeter Maydell 
1170712182d3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1171712182d3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1172712182d3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1173712182d3SPeter Maydell         return false;
1174712182d3SPeter Maydell     }
1175712182d3SPeter Maydell 
1176712182d3SPeter Maydell     if (a->vm & 1) {
1177712182d3SPeter Maydell         return false;
1178712182d3SPeter Maydell     }
1179712182d3SPeter Maydell 
1180712182d3SPeter Maydell     if (!vfp_access_check(s)) {
1181712182d3SPeter Maydell         return true;
1182712182d3SPeter Maydell     }
1183712182d3SPeter Maydell 
1184712182d3SPeter Maydell     /*
1185712182d3SPeter Maydell      * This is always a right shift, and the shiftfn is always a
1186712182d3SPeter Maydell      * left-shift helper, which thus needs the negated shift count
1187712182d3SPeter Maydell      * duplicated into each lane of the immediate value.
1188712182d3SPeter Maydell      */
1189712182d3SPeter Maydell     if (a->size == 1) {
1190712182d3SPeter Maydell         imm = (uint16_t)(-a->shift);
1191712182d3SPeter Maydell         imm |= imm << 16;
1192712182d3SPeter Maydell     } else {
1193712182d3SPeter Maydell         /* size == 2 */
1194712182d3SPeter Maydell         imm = -a->shift;
1195712182d3SPeter Maydell     }
1196d9b47e97SRichard Henderson     constimm = tcg_constant_i32(imm);
1197712182d3SPeter Maydell 
1198712182d3SPeter Maydell     /* Load all inputs first to avoid potential overwrite */
1199a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
1200a712266fSRichard Henderson     rm2 = tcg_temp_new_i32();
1201a712266fSRichard Henderson     rm3 = tcg_temp_new_i32();
1202a712266fSRichard Henderson     rm4 = tcg_temp_new_i32();
1203a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 0, MO_32);
1204a712266fSRichard Henderson     read_neon_element32(rm2, a->vm, 1, MO_32);
1205a712266fSRichard Henderson     read_neon_element32(rm3, a->vm, 2, MO_32);
1206a712266fSRichard Henderson     read_neon_element32(rm4, a->vm, 3, MO_32);
1207712182d3SPeter Maydell     rtmp = tcg_temp_new_i64();
1208712182d3SPeter Maydell 
1209712182d3SPeter Maydell     shiftfn(rm1, rm1, constimm);
1210712182d3SPeter Maydell     shiftfn(rm2, rm2, constimm);
1211712182d3SPeter Maydell 
1212712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
1213712182d3SPeter Maydell 
12143e683f0aSRichard Henderson     narrowfn(rtmp, tcg_env, rtmp);
12153e683f0aSRichard Henderson     write_neon_element64(rtmp, a->vd, 0, MO_32);
1216712182d3SPeter Maydell 
1217712182d3SPeter Maydell     shiftfn(rm3, rm3, constimm);
1218712182d3SPeter Maydell     shiftfn(rm4, rm4, constimm);
1219712182d3SPeter Maydell 
1220712182d3SPeter Maydell     tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
1221712182d3SPeter Maydell 
12223e683f0aSRichard Henderson     narrowfn(rtmp, tcg_env, rtmp);
12233e683f0aSRichard Henderson     write_neon_element64(rtmp, a->vd, 1, MO_32);
1224712182d3SPeter Maydell     return true;
1225712182d3SPeter Maydell }
1226712182d3SPeter Maydell 
1227712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC)                               \
1228712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1229712182d3SPeter Maydell     {                                                                   \
1230712182d3SPeter Maydell         return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC);             \
1231712182d3SPeter Maydell     }
1232712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC)                               \
1233712182d3SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
1234712182d3SPeter Maydell     {                                                                   \
1235712182d3SPeter Maydell         return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC);             \
1236712182d3SPeter Maydell     }
1237712182d3SPeter Maydell 
gen_neon_narrow_u32(TCGv_i64 dest,TCGv_ptr env,TCGv_i64 src)12383e683f0aSRichard Henderson static void gen_neon_narrow_u32(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
1239712182d3SPeter Maydell {
12403e683f0aSRichard Henderson     tcg_gen_ext32u_i64(dest, src);
1241712182d3SPeter Maydell }
1242712182d3SPeter Maydell 
gen_neon_narrow_u16(TCGv_i64 dest,TCGv_ptr env,TCGv_i64 src)12433e683f0aSRichard Henderson static void gen_neon_narrow_u16(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
1244712182d3SPeter Maydell {
1245712182d3SPeter Maydell     gen_helper_neon_narrow_u16(dest, src);
1246712182d3SPeter Maydell }
1247712182d3SPeter Maydell 
gen_neon_narrow_u8(TCGv_i64 dest,TCGv_ptr env,TCGv_i64 src)12483e683f0aSRichard Henderson static void gen_neon_narrow_u8(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
1249712182d3SPeter Maydell {
1250712182d3SPeter Maydell     gen_helper_neon_narrow_u8(dest, src);
1251712182d3SPeter Maydell }
1252712182d3SPeter Maydell 
DO_2SN_64(VSHRN_64,gen_ushl_i64,gen_neon_narrow_u32)1253712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32)
1254712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16)
1255712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8)
1256712182d3SPeter Maydell 
1257712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32)
1258712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16)
1259712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8)
1260712182d3SPeter Maydell 
1261712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32)
1262712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16)
1263712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8)
1264712182d3SPeter Maydell 
1265712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32)
1266712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16)
1267712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8)
1268b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32)
1269b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16)
1270b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8)
1271b4a3a77bSPeter Maydell 
1272b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32)
1273b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16)
1274b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8)
1275b4a3a77bSPeter Maydell 
1276b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32)
1277b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16)
1278b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8)
1279b4a3a77bSPeter Maydell 
1280b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32)
1281b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16)
1282b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8)
1283968bf842SPeter Maydell 
1284968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a,
1285968bf842SPeter Maydell                          NeonGenWidenFn *widenfn, bool u)
1286968bf842SPeter Maydell {
1287968bf842SPeter Maydell     TCGv_i64 tmp;
1288968bf842SPeter Maydell     TCGv_i32 rm0, rm1;
1289968bf842SPeter Maydell     uint64_t widen_mask = 0;
1290968bf842SPeter Maydell 
1291968bf842SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1292968bf842SPeter Maydell         return false;
1293968bf842SPeter Maydell     }
1294968bf842SPeter Maydell 
1295968bf842SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1296968bf842SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1297968bf842SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
1298968bf842SPeter Maydell         return false;
1299968bf842SPeter Maydell     }
1300968bf842SPeter Maydell 
1301968bf842SPeter Maydell     if (a->vd & 1) {
1302968bf842SPeter Maydell         return false;
1303968bf842SPeter Maydell     }
1304968bf842SPeter Maydell 
1305968bf842SPeter Maydell     if (!vfp_access_check(s)) {
1306968bf842SPeter Maydell         return true;
1307968bf842SPeter Maydell     }
1308968bf842SPeter Maydell 
1309968bf842SPeter Maydell     /*
1310968bf842SPeter Maydell      * This is a widen-and-shift operation. The shift is always less
1311968bf842SPeter Maydell      * than the width of the source type, so after widening the input
1312968bf842SPeter Maydell      * vector we can simply shift the whole 64-bit widened register,
1313968bf842SPeter Maydell      * and then clear the potential overflow bits resulting from left
1314968bf842SPeter Maydell      * bits of the narrow input appearing as right bits of the left
1315968bf842SPeter Maydell      * neighbour narrow input. Calculate a mask of bits to clear.
1316968bf842SPeter Maydell      */
1317968bf842SPeter Maydell     if ((a->shift != 0) && (a->size < 2 || u)) {
1318968bf842SPeter Maydell         int esize = 8 << a->size;
1319968bf842SPeter Maydell         widen_mask = MAKE_64BIT_MASK(0, esize);
1320968bf842SPeter Maydell         widen_mask >>= esize - a->shift;
1321968bf842SPeter Maydell         widen_mask = dup_const(a->size + 1, widen_mask);
1322968bf842SPeter Maydell     }
1323968bf842SPeter Maydell 
1324a712266fSRichard Henderson     rm0 = tcg_temp_new_i32();
1325a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
1326a712266fSRichard Henderson     read_neon_element32(rm0, a->vm, 0, MO_32);
1327a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 1, MO_32);
1328968bf842SPeter Maydell     tmp = tcg_temp_new_i64();
1329968bf842SPeter Maydell 
1330968bf842SPeter Maydell     widenfn(tmp, rm0);
1331968bf842SPeter Maydell     if (a->shift != 0) {
1332968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1333968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1334968bf842SPeter Maydell     }
13350aa8e700SRichard Henderson     write_neon_element64(tmp, a->vd, 0, MO_64);
1336968bf842SPeter Maydell 
1337968bf842SPeter Maydell     widenfn(tmp, rm1);
1338968bf842SPeter Maydell     if (a->shift != 0) {
1339968bf842SPeter Maydell         tcg_gen_shli_i64(tmp, tmp, a->shift);
1340968bf842SPeter Maydell         tcg_gen_andi_i64(tmp, tmp, ~widen_mask);
1341968bf842SPeter Maydell     }
13420aa8e700SRichard Henderson     write_neon_element64(tmp, a->vd, 1, MO_64);
1343968bf842SPeter Maydell     return true;
1344968bf842SPeter Maydell }
1345968bf842SPeter Maydell 
trans_VSHLL_S_2sh(DisasContext * s,arg_2reg_shift * a)1346968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a)
1347968bf842SPeter Maydell {
1348448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1349968bf842SPeter Maydell         gen_helper_neon_widen_s8,
1350968bf842SPeter Maydell         gen_helper_neon_widen_s16,
1351968bf842SPeter Maydell         tcg_gen_ext_i32_i64,
1352968bf842SPeter Maydell     };
1353968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], false);
1354968bf842SPeter Maydell }
1355968bf842SPeter Maydell 
trans_VSHLL_U_2sh(DisasContext * s,arg_2reg_shift * a)1356968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
1357968bf842SPeter Maydell {
1358448f0e5fSPeter Maydell     static NeonGenWidenFn * const widenfn[] = {
1359968bf842SPeter Maydell         gen_helper_neon_widen_u8,
1360968bf842SPeter Maydell         gen_helper_neon_widen_u16,
1361968bf842SPeter Maydell         tcg_gen_extu_i32_i64,
1362968bf842SPeter Maydell     };
1363968bf842SPeter Maydell     return do_vshll_2sh(s, a, widenfn[a->size], true);
1364968bf842SPeter Maydell }
13653da26f11SPeter Maydell 
do_fp_2sh(DisasContext * s,arg_2reg_shift * a,gen_helper_gvec_2_ptr * fn)13663da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
13677b959c58SPeter Maydell                       gen_helper_gvec_2_ptr *fn)
13683da26f11SPeter Maydell {
13693da26f11SPeter Maydell     /* FP operations in 2-reg-and-shift group */
13707b959c58SPeter Maydell     int vec_size = a->q ? 16 : 8;
1371015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
1372015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
13737b959c58SPeter Maydell     TCGv_ptr fpst;
13743da26f11SPeter Maydell 
13753da26f11SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
13763da26f11SPeter Maydell         return false;
13773da26f11SPeter Maydell     }
13783da26f11SPeter Maydell 
13790ae715c6SPeter Maydell     if (a->size == MO_16) {
13807b959c58SPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
13817b959c58SPeter Maydell             return false;
13827b959c58SPeter Maydell         }
13837b959c58SPeter Maydell     }
13847b959c58SPeter Maydell 
13853da26f11SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
13863da26f11SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
13873da26f11SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
13883da26f11SPeter Maydell         return false;
13893da26f11SPeter Maydell     }
13903da26f11SPeter Maydell 
13913da26f11SPeter Maydell     if ((a->vm | a->vd) & a->q) {
13923da26f11SPeter Maydell         return false;
13933da26f11SPeter Maydell     }
13943da26f11SPeter Maydell 
13953da26f11SPeter Maydell     if (!vfp_access_check(s)) {
13963da26f11SPeter Maydell         return true;
13973da26f11SPeter Maydell     }
13983da26f11SPeter Maydell 
13990ae715c6SPeter Maydell     fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD);
14007b959c58SPeter Maydell     tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn);
14013da26f11SPeter Maydell     return true;
14023da26f11SPeter Maydell }
14033da26f11SPeter Maydell 
14043da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC)                                           \
14053da26f11SPeter Maydell     static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a)  \
14063da26f11SPeter Maydell     {                                                                   \
14073da26f11SPeter Maydell         return do_fp_2sh(s, a, FUNC);                                   \
14083da26f11SPeter Maydell     }
14093da26f11SPeter Maydell 
DO_FP_2SH(VCVT_SF,gen_helper_gvec_vcvt_sf)14107b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf)
14117b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf)
1412c2e13388SRichard Henderson DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_rz_fs)
1413c2e13388SRichard Henderson DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_rz_fu)
14142c35a39eSPeter Maydell 
141524018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh)
141624018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh)
1417c2e13388SRichard Henderson DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_rz_hs)
1418c2e13388SRichard Henderson DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_rz_hu)
141924018cf3SPeter Maydell 
14202c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a,
14212c35a39eSPeter Maydell                         GVecGen2iFn *fn)
14222c35a39eSPeter Maydell {
14232c35a39eSPeter Maydell     uint64_t imm;
14242c35a39eSPeter Maydell     int reg_ofs, vec_size;
14252c35a39eSPeter Maydell 
14262c35a39eSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
14272c35a39eSPeter Maydell         return false;
14282c35a39eSPeter Maydell     }
14292c35a39eSPeter Maydell 
14302c35a39eSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
14312c35a39eSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
14322c35a39eSPeter Maydell         return false;
14332c35a39eSPeter Maydell     }
14342c35a39eSPeter Maydell 
14352c35a39eSPeter Maydell     if (a->vd & a->q) {
14362c35a39eSPeter Maydell         return false;
14372c35a39eSPeter Maydell     }
14382c35a39eSPeter Maydell 
14392c35a39eSPeter Maydell     if (!vfp_access_check(s)) {
14402c35a39eSPeter Maydell         return true;
14412c35a39eSPeter Maydell     }
14422c35a39eSPeter Maydell 
1443015ee81aSRichard Henderson     reg_ofs = neon_full_reg_offset(a->vd);
14442c35a39eSPeter Maydell     vec_size = a->q ? 16 : 8;
14452c35a39eSPeter Maydell     imm = asimd_imm_const(a->imm, a->cmode, a->op);
14462c35a39eSPeter Maydell 
14472c35a39eSPeter Maydell     fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size);
14482c35a39eSPeter Maydell     return true;
14492c35a39eSPeter Maydell }
14502c35a39eSPeter Maydell 
gen_VMOV_1r(unsigned vece,uint32_t dofs,uint32_t aofs,int64_t c,uint32_t oprsz,uint32_t maxsz)14512c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs,
14522c35a39eSPeter Maydell                         int64_t c, uint32_t oprsz, uint32_t maxsz)
14532c35a39eSPeter Maydell {
14542c35a39eSPeter Maydell     tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
14552c35a39eSPeter Maydell }
14562c35a39eSPeter Maydell 
trans_Vimm_1r(DisasContext * s,arg_1reg_imm * a)14572c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a)
14582c35a39eSPeter Maydell {
14592c35a39eSPeter Maydell     /* Handle decode of cmode/op here between VORR/VBIC/VMOV */
14602c35a39eSPeter Maydell     GVecGen2iFn *fn;
14612c35a39eSPeter Maydell 
14622c35a39eSPeter Maydell     if ((a->cmode & 1) && a->cmode < 12) {
14632c35a39eSPeter Maydell         /* for op=1, the imm will be inverted, so BIC becomes AND. */
14642c35a39eSPeter Maydell         fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
14652c35a39eSPeter Maydell     } else {
14662c35a39eSPeter Maydell         /* There is one unallocated cmode/op combination in this space */
14672c35a39eSPeter Maydell         if (a->cmode == 15 && a->op == 1) {
14682c35a39eSPeter Maydell             return false;
14692c35a39eSPeter Maydell         }
14702c35a39eSPeter Maydell         fn = gen_VMOV_1r;
14712c35a39eSPeter Maydell     }
14722c35a39eSPeter Maydell     return do_1reg_imm(s, a, fn);
14732c35a39eSPeter Maydell }
1474b28be095SPeter Maydell 
do_prewiden_3d(DisasContext * s,arg_3diff * a,NeonGenWidenFn * widenfn,NeonGenTwo64OpFn * opfn,int src1_mop,int src2_mop)1475b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a,
1476b28be095SPeter Maydell                            NeonGenWidenFn *widenfn,
1477b28be095SPeter Maydell                            NeonGenTwo64OpFn *opfn,
14788aab18a2SRichard Henderson                            int src1_mop, int src2_mop)
1479b28be095SPeter Maydell {
1480b28be095SPeter Maydell     /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */
1481b28be095SPeter Maydell     TCGv_i64 rn0_64, rn1_64, rm_64;
1482b28be095SPeter Maydell 
1483b28be095SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1484b28be095SPeter Maydell         return false;
1485b28be095SPeter Maydell     }
1486b28be095SPeter Maydell 
1487b28be095SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1488b28be095SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1489b28be095SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1490b28be095SPeter Maydell         return false;
1491b28be095SPeter Maydell     }
1492b28be095SPeter Maydell 
14938aab18a2SRichard Henderson     if (!opfn) {
1494b28be095SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
1495b28be095SPeter Maydell         return false;
1496b28be095SPeter Maydell     }
1497b28be095SPeter Maydell 
1498fc313c64SFrédéric Pétrot     if ((a->vd & 1) || (src1_mop == MO_UQ && (a->vn & 1))) {
1499b28be095SPeter Maydell         return false;
1500b28be095SPeter Maydell     }
1501b28be095SPeter Maydell 
1502b28be095SPeter Maydell     if (!vfp_access_check(s)) {
1503b28be095SPeter Maydell         return true;
1504b28be095SPeter Maydell     }
1505b28be095SPeter Maydell 
1506b28be095SPeter Maydell     rn0_64 = tcg_temp_new_i64();
1507b28be095SPeter Maydell     rn1_64 = tcg_temp_new_i64();
1508b28be095SPeter Maydell     rm_64 = tcg_temp_new_i64();
1509b28be095SPeter Maydell 
15108aab18a2SRichard Henderson     if (src1_mop >= 0) {
15118aab18a2SRichard Henderson         read_neon_element64(rn0_64, a->vn, 0, src1_mop);
1512b28be095SPeter Maydell     } else {
1513a712266fSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
1514a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, 0, MO_32);
1515b28be095SPeter Maydell         widenfn(rn0_64, tmp);
1516b28be095SPeter Maydell     }
15178aab18a2SRichard Henderson     if (src2_mop >= 0) {
15188aab18a2SRichard Henderson         read_neon_element64(rm_64, a->vm, 0, src2_mop);
15198aab18a2SRichard Henderson     } else {
15208aab18a2SRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
15218aab18a2SRichard Henderson         read_neon_element32(tmp, a->vm, 0, MO_32);
15228aab18a2SRichard Henderson         widenfn(rm_64, tmp);
15238aab18a2SRichard Henderson     }
1524b28be095SPeter Maydell 
1525b28be095SPeter Maydell     opfn(rn0_64, rn0_64, rm_64);
1526b28be095SPeter Maydell 
1527b28be095SPeter Maydell     /*
1528b28be095SPeter Maydell      * Load second pass inputs before storing the first pass result, to
1529b28be095SPeter Maydell      * avoid incorrect results if a narrow input overlaps with the result.
1530b28be095SPeter Maydell      */
15318aab18a2SRichard Henderson     if (src1_mop >= 0) {
15328aab18a2SRichard Henderson         read_neon_element64(rn1_64, a->vn, 1, src1_mop);
1533b28be095SPeter Maydell     } else {
1534a712266fSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
1535a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, 1, MO_32);
1536b28be095SPeter Maydell         widenfn(rn1_64, tmp);
1537b28be095SPeter Maydell     }
15388aab18a2SRichard Henderson     if (src2_mop >= 0) {
15398aab18a2SRichard Henderson         read_neon_element64(rm_64, a->vm, 1, src2_mop);
15408aab18a2SRichard Henderson     } else {
15418aab18a2SRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
15428aab18a2SRichard Henderson         read_neon_element32(tmp, a->vm, 1, MO_32);
15438aab18a2SRichard Henderson         widenfn(rm_64, tmp);
15448aab18a2SRichard Henderson     }
1545b28be095SPeter Maydell 
15460aa8e700SRichard Henderson     write_neon_element64(rn0_64, a->vd, 0, MO_64);
1547b28be095SPeter Maydell 
1548b28be095SPeter Maydell     opfn(rn1_64, rn1_64, rm_64);
15490aa8e700SRichard Henderson     write_neon_element64(rn1_64, a->vd, 1, MO_64);
1550b28be095SPeter Maydell 
1551b28be095SPeter Maydell     return true;
1552b28be095SPeter Maydell }
1553b28be095SPeter Maydell 
15548aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN)                        \
1555b28be095SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
1556b28be095SPeter Maydell     {                                                                   \
1557b28be095SPeter Maydell         static NeonGenWidenFn * const widenfn[] = {                     \
1558b28be095SPeter Maydell             gen_helper_neon_widen_##S##8,                               \
1559b28be095SPeter Maydell             gen_helper_neon_widen_##S##16,                              \
15608aab18a2SRichard Henderson             NULL, NULL,                                                 \
1561b28be095SPeter Maydell         };                                                              \
1562b28be095SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
156307e0d7a0SRichard Henderson             tcg_gen_vec_##OP##16_i64,                                   \
156407e0d7a0SRichard Henderson             tcg_gen_vec_##OP##32_i64,                                   \
1565b28be095SPeter Maydell             tcg_gen_##OP##_i64,                                         \
1566b28be095SPeter Maydell             NULL,                                                       \
1567b28be095SPeter Maydell         };                                                              \
15688aab18a2SRichard Henderson         int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1;          \
15698aab18a2SRichard Henderson         return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size],   \
1570fc313c64SFrédéric Pétrot                               SRC1WIDE ? MO_UQ : narrow_mop,             \
15718aab18a2SRichard Henderson                               narrow_mop);                              \
1572b28be095SPeter Maydell     }
1573b28be095SPeter Maydell 
DO_PREWIDEN(VADDL_S,s,add,false,MO_SIGN)15748aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN)
15758aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0)
15768aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN)
15778aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0)
15788aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN)
15798aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0)
15808aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN)
15818aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0)
15820fa1ab03SPeter Maydell 
15830fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a,
15840fa1ab03SPeter Maydell                          NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn)
15850fa1ab03SPeter Maydell {
15860fa1ab03SPeter Maydell     /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */
15870fa1ab03SPeter Maydell     TCGv_i64 rn_64, rm_64;
15880fa1ab03SPeter Maydell     TCGv_i32 rd0, rd1;
15890fa1ab03SPeter Maydell 
15900fa1ab03SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
15910fa1ab03SPeter Maydell         return false;
15920fa1ab03SPeter Maydell     }
15930fa1ab03SPeter Maydell 
15940fa1ab03SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
15950fa1ab03SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
15960fa1ab03SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
15970fa1ab03SPeter Maydell         return false;
15980fa1ab03SPeter Maydell     }
15990fa1ab03SPeter Maydell 
16000fa1ab03SPeter Maydell     if (!opfn || !narrowfn) {
16010fa1ab03SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
16020fa1ab03SPeter Maydell         return false;
16030fa1ab03SPeter Maydell     }
16040fa1ab03SPeter Maydell 
16050fa1ab03SPeter Maydell     if ((a->vn | a->vm) & 1) {
16060fa1ab03SPeter Maydell         return false;
16070fa1ab03SPeter Maydell     }
16080fa1ab03SPeter Maydell 
16090fa1ab03SPeter Maydell     if (!vfp_access_check(s)) {
16100fa1ab03SPeter Maydell         return true;
16110fa1ab03SPeter Maydell     }
16120fa1ab03SPeter Maydell 
16130fa1ab03SPeter Maydell     rn_64 = tcg_temp_new_i64();
16140fa1ab03SPeter Maydell     rm_64 = tcg_temp_new_i64();
16150fa1ab03SPeter Maydell     rd0 = tcg_temp_new_i32();
16160fa1ab03SPeter Maydell     rd1 = tcg_temp_new_i32();
16170fa1ab03SPeter Maydell 
16180aa8e700SRichard Henderson     read_neon_element64(rn_64, a->vn, 0, MO_64);
16190aa8e700SRichard Henderson     read_neon_element64(rm_64, a->vm, 0, MO_64);
16200fa1ab03SPeter Maydell 
16210fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
16220fa1ab03SPeter Maydell 
16230fa1ab03SPeter Maydell     narrowfn(rd0, rn_64);
16240fa1ab03SPeter Maydell 
16250aa8e700SRichard Henderson     read_neon_element64(rn_64, a->vn, 1, MO_64);
16260aa8e700SRichard Henderson     read_neon_element64(rm_64, a->vm, 1, MO_64);
16270fa1ab03SPeter Maydell 
16280fa1ab03SPeter Maydell     opfn(rn_64, rn_64, rm_64);
16290fa1ab03SPeter Maydell 
16300fa1ab03SPeter Maydell     narrowfn(rd1, rn_64);
16310fa1ab03SPeter Maydell 
1632a712266fSRichard Henderson     write_neon_element32(rd0, a->vd, 0, MO_32);
1633a712266fSRichard Henderson     write_neon_element32(rd1, a->vd, 1, MO_32);
16340fa1ab03SPeter Maydell 
16350fa1ab03SPeter Maydell     return true;
16360fa1ab03SPeter Maydell }
16370fa1ab03SPeter Maydell 
16380fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP)                       \
16390fa1ab03SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
16400fa1ab03SPeter Maydell     {                                                                   \
16410fa1ab03SPeter Maydell         static NeonGenTwo64OpFn * const addfn[] = {                     \
164207e0d7a0SRichard Henderson             tcg_gen_vec_##OP##16_i64,                                   \
164307e0d7a0SRichard Henderson             tcg_gen_vec_##OP##32_i64,                                   \
16440fa1ab03SPeter Maydell             tcg_gen_##OP##_i64,                                         \
16450fa1ab03SPeter Maydell             NULL,                                                       \
16460fa1ab03SPeter Maydell         };                                                              \
16470fa1ab03SPeter Maydell         static NeonGenNarrowFn * const narrowfn[] = {                   \
16480fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u8,                     \
16490fa1ab03SPeter Maydell             gen_helper_neon_##NARROWTYPE##_high_u16,                    \
16500fa1ab03SPeter Maydell             EXTOP,                                                      \
16510fa1ab03SPeter Maydell             NULL,                                                       \
16520fa1ab03SPeter Maydell         };                                                              \
16530fa1ab03SPeter Maydell         return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]);   \
16540fa1ab03SPeter Maydell     }
16550fa1ab03SPeter Maydell 
gen_narrow_round_high_u32(TCGv_i32 rd,TCGv_i64 rn)16560fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn)
16570fa1ab03SPeter Maydell {
16580fa1ab03SPeter Maydell     tcg_gen_addi_i64(rn, rn, 1u << 31);
16590fa1ab03SPeter Maydell     tcg_gen_extrh_i64_i32(rd, rn);
16600fa1ab03SPeter Maydell }
16610fa1ab03SPeter Maydell 
DO_NARROW_3D(VADDHN,add,narrow,tcg_gen_extrh_i64_i32)16620fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32)
16630fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32)
16640fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32)
16650fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32)
1666f5b28401SPeter Maydell 
1667f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a,
1668f5b28401SPeter Maydell                        NeonGenTwoOpWidenFn *opfn,
1669f5b28401SPeter Maydell                        NeonGenTwo64OpFn *accfn)
1670f5b28401SPeter Maydell {
1671f5b28401SPeter Maydell     /*
1672f5b28401SPeter Maydell      * 3-regs different lengths, long operations.
1673f5b28401SPeter Maydell      * These perform an operation on two inputs that returns a double-width
1674f5b28401SPeter Maydell      * result, and then possibly perform an accumulation operation of
1675f5b28401SPeter Maydell      * that result into the double-width destination.
1676f5b28401SPeter Maydell      */
1677f5b28401SPeter Maydell     TCGv_i64 rd0, rd1, tmp;
1678f5b28401SPeter Maydell     TCGv_i32 rn, rm;
1679f5b28401SPeter Maydell 
1680f5b28401SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
1681f5b28401SPeter Maydell         return false;
1682f5b28401SPeter Maydell     }
1683f5b28401SPeter Maydell 
1684f5b28401SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1685f5b28401SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1686f5b28401SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1687f5b28401SPeter Maydell         return false;
1688f5b28401SPeter Maydell     }
1689f5b28401SPeter Maydell 
1690f5b28401SPeter Maydell     if (!opfn) {
1691f5b28401SPeter Maydell         /* size == 3 case, which is an entirely different insn group */
1692f5b28401SPeter Maydell         return false;
1693f5b28401SPeter Maydell     }
1694f5b28401SPeter Maydell 
1695f5b28401SPeter Maydell     if (a->vd & 1) {
1696f5b28401SPeter Maydell         return false;
1697f5b28401SPeter Maydell     }
1698f5b28401SPeter Maydell 
1699f5b28401SPeter Maydell     if (!vfp_access_check(s)) {
1700f5b28401SPeter Maydell         return true;
1701f5b28401SPeter Maydell     }
1702f5b28401SPeter Maydell 
1703f5b28401SPeter Maydell     rd0 = tcg_temp_new_i64();
1704f5b28401SPeter Maydell     rd1 = tcg_temp_new_i64();
1705f5b28401SPeter Maydell 
1706a712266fSRichard Henderson     rn = tcg_temp_new_i32();
1707a712266fSRichard Henderson     rm = tcg_temp_new_i32();
1708a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 0, MO_32);
1709a712266fSRichard Henderson     read_neon_element32(rm, a->vm, 0, MO_32);
1710f5b28401SPeter Maydell     opfn(rd0, rn, rm);
1711f5b28401SPeter Maydell 
1712a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 1, MO_32);
1713a712266fSRichard Henderson     read_neon_element32(rm, a->vm, 1, MO_32);
1714f5b28401SPeter Maydell     opfn(rd1, rn, rm);
1715f5b28401SPeter Maydell 
1716f5b28401SPeter Maydell     /* Don't store results until after all loads: they might overlap */
1717f5b28401SPeter Maydell     if (accfn) {
1718f5b28401SPeter Maydell         tmp = tcg_temp_new_i64();
17190aa8e700SRichard Henderson         read_neon_element64(tmp, a->vd, 0, MO_64);
17209f1a5f93SRichard Henderson         accfn(rd0, tmp, rd0);
17210aa8e700SRichard Henderson         read_neon_element64(tmp, a->vd, 1, MO_64);
17229f1a5f93SRichard Henderson         accfn(rd1, tmp, rd1);
1723f5b28401SPeter Maydell     }
1724f5b28401SPeter Maydell 
17259f1a5f93SRichard Henderson     write_neon_element64(rd0, a->vd, 0, MO_64);
17269f1a5f93SRichard Henderson     write_neon_element64(rd1, a->vd, 1, MO_64);
1727f5b28401SPeter Maydell 
1728f5b28401SPeter Maydell     return true;
1729f5b28401SPeter Maydell }
1730f5b28401SPeter Maydell 
trans_VABDL_S_3d(DisasContext * s,arg_3diff * a)1731f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a)
1732f5b28401SPeter Maydell {
1733f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
1734f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
1735f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
1736f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
1737f5b28401SPeter Maydell         NULL,
1738f5b28401SPeter Maydell     };
1739f5b28401SPeter Maydell 
1740f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
1741f5b28401SPeter Maydell }
1742f5b28401SPeter Maydell 
trans_VABDL_U_3d(DisasContext * s,arg_3diff * a)1743f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a)
1744f5b28401SPeter Maydell {
1745f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
1746f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
1747f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
1748f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
1749f5b28401SPeter Maydell         NULL,
1750f5b28401SPeter Maydell     };
1751f5b28401SPeter Maydell 
1752f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
1753f5b28401SPeter Maydell }
1754f5b28401SPeter Maydell 
trans_VABAL_S_3d(DisasContext * s,arg_3diff * a)1755f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a)
1756f5b28401SPeter Maydell {
1757f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
1758f5b28401SPeter Maydell         gen_helper_neon_abdl_s16,
1759f5b28401SPeter Maydell         gen_helper_neon_abdl_s32,
1760f5b28401SPeter Maydell         gen_helper_neon_abdl_s64,
1761f5b28401SPeter Maydell         NULL,
1762f5b28401SPeter Maydell     };
1763f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
176407e0d7a0SRichard Henderson         tcg_gen_vec_add16_i64,
176507e0d7a0SRichard Henderson         tcg_gen_vec_add32_i64,
1766f5b28401SPeter Maydell         tcg_gen_add_i64,
1767f5b28401SPeter Maydell         NULL,
1768f5b28401SPeter Maydell     };
1769f5b28401SPeter Maydell 
1770f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
1771f5b28401SPeter Maydell }
1772f5b28401SPeter Maydell 
trans_VABAL_U_3d(DisasContext * s,arg_3diff * a)1773f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
1774f5b28401SPeter Maydell {
1775f5b28401SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
1776f5b28401SPeter Maydell         gen_helper_neon_abdl_u16,
1777f5b28401SPeter Maydell         gen_helper_neon_abdl_u32,
1778f5b28401SPeter Maydell         gen_helper_neon_abdl_u64,
1779f5b28401SPeter Maydell         NULL,
1780f5b28401SPeter Maydell     };
1781f5b28401SPeter Maydell     static NeonGenTwo64OpFn * const addfn[] = {
178207e0d7a0SRichard Henderson         tcg_gen_vec_add16_i64,
178307e0d7a0SRichard Henderson         tcg_gen_vec_add32_i64,
1784f5b28401SPeter Maydell         tcg_gen_add_i64,
1785f5b28401SPeter Maydell         NULL,
1786f5b28401SPeter Maydell     };
1787f5b28401SPeter Maydell 
1788f5b28401SPeter Maydell     return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
1789f5b28401SPeter Maydell }
17903a1d9eb0SPeter Maydell 
gen_mull_s32(TCGv_i64 rd,TCGv_i32 rn,TCGv_i32 rm)17913a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
17923a1d9eb0SPeter Maydell {
17933a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
17943a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
17953a1d9eb0SPeter Maydell 
17963a1d9eb0SPeter Maydell     tcg_gen_muls2_i32(lo, hi, rn, rm);
17973a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
17983a1d9eb0SPeter Maydell }
17993a1d9eb0SPeter Maydell 
gen_mull_u32(TCGv_i64 rd,TCGv_i32 rn,TCGv_i32 rm)18003a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
18013a1d9eb0SPeter Maydell {
18023a1d9eb0SPeter Maydell     TCGv_i32 lo = tcg_temp_new_i32();
18033a1d9eb0SPeter Maydell     TCGv_i32 hi = tcg_temp_new_i32();
18043a1d9eb0SPeter Maydell 
18053a1d9eb0SPeter Maydell     tcg_gen_mulu2_i32(lo, hi, rn, rm);
18063a1d9eb0SPeter Maydell     tcg_gen_concat_i32_i64(rd, lo, hi);
18073a1d9eb0SPeter Maydell }
18083a1d9eb0SPeter Maydell 
trans_VMULL_S_3d(DisasContext * s,arg_3diff * a)18093a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a)
18103a1d9eb0SPeter Maydell {
18113a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
18123a1d9eb0SPeter Maydell         gen_helper_neon_mull_s8,
18133a1d9eb0SPeter Maydell         gen_helper_neon_mull_s16,
18143a1d9eb0SPeter Maydell         gen_mull_s32,
18153a1d9eb0SPeter Maydell         NULL,
18163a1d9eb0SPeter Maydell     };
18173a1d9eb0SPeter Maydell 
18183a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
18193a1d9eb0SPeter Maydell }
18203a1d9eb0SPeter Maydell 
trans_VMULL_U_3d(DisasContext * s,arg_3diff * a)18213a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
18223a1d9eb0SPeter Maydell {
18233a1d9eb0SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
18243a1d9eb0SPeter Maydell         gen_helper_neon_mull_u8,
18253a1d9eb0SPeter Maydell         gen_helper_neon_mull_u16,
18263a1d9eb0SPeter Maydell         gen_mull_u32,
18273a1d9eb0SPeter Maydell         NULL,
18283a1d9eb0SPeter Maydell     };
18293a1d9eb0SPeter Maydell 
18303a1d9eb0SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
18313a1d9eb0SPeter Maydell }
18323a1d9eb0SPeter Maydell 
18333a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC)                                         \
18343a1d9eb0SPeter Maydell     static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a)        \
18353a1d9eb0SPeter Maydell     {                                                                   \
18363a1d9eb0SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
18373a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##8,                                  \
18383a1d9eb0SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
18393a1d9eb0SPeter Maydell             gen_##MULL##32,                                             \
18403a1d9eb0SPeter Maydell             NULL,                                                       \
18413a1d9eb0SPeter Maydell         };                                                              \
18423a1d9eb0SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
184307e0d7a0SRichard Henderson             tcg_gen_vec_##ACC##16_i64,                                  \
184407e0d7a0SRichard Henderson             tcg_gen_vec_##ACC##32_i64,                                  \
18453a1d9eb0SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
18463a1d9eb0SPeter Maydell             NULL,                                                       \
18473a1d9eb0SPeter Maydell         };                                                              \
18483a1d9eb0SPeter Maydell         return do_long_3d(s, a, opfn[a->size], accfn[a->size]);         \
18493a1d9eb0SPeter Maydell     }
18503a1d9eb0SPeter Maydell 
DO_VMLAL(VMLAL_S,mull_s,add)18513a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add)
18523a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add)
18533a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub)
18543a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub)
18559546ca59SPeter Maydell 
18569546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
18579546ca59SPeter Maydell {
18589546ca59SPeter Maydell     gen_helper_neon_mull_s16(rd, rn, rm);
1859ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s32(rd, tcg_env, rd, rd);
18609546ca59SPeter Maydell }
18619546ca59SPeter Maydell 
gen_VQDMULL_32(TCGv_i64 rd,TCGv_i32 rn,TCGv_i32 rm)18629546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
18639546ca59SPeter Maydell {
18649546ca59SPeter Maydell     gen_mull_s32(rd, rn, rm);
1865ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s64(rd, tcg_env, rd, rd);
18669546ca59SPeter Maydell }
18679546ca59SPeter Maydell 
trans_VQDMULL_3d(DisasContext * s,arg_3diff * a)18689546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a)
18699546ca59SPeter Maydell {
18709546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
18719546ca59SPeter Maydell         NULL,
18729546ca59SPeter Maydell         gen_VQDMULL_16,
18739546ca59SPeter Maydell         gen_VQDMULL_32,
18749546ca59SPeter Maydell         NULL,
18759546ca59SPeter Maydell     };
18769546ca59SPeter Maydell 
18779546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], NULL);
18789546ca59SPeter Maydell }
18799546ca59SPeter Maydell 
gen_VQDMLAL_acc_16(TCGv_i64 rd,TCGv_i64 rn,TCGv_i64 rm)18809546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
18819546ca59SPeter Maydell {
1882ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm);
18839546ca59SPeter Maydell }
18849546ca59SPeter Maydell 
gen_VQDMLAL_acc_32(TCGv_i64 rd,TCGv_i64 rn,TCGv_i64 rm)18859546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
18869546ca59SPeter Maydell {
1887ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm);
18889546ca59SPeter Maydell }
18899546ca59SPeter Maydell 
trans_VQDMLAL_3d(DisasContext * s,arg_3diff * a)18909546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a)
18919546ca59SPeter Maydell {
18929546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
18939546ca59SPeter Maydell         NULL,
18949546ca59SPeter Maydell         gen_VQDMULL_16,
18959546ca59SPeter Maydell         gen_VQDMULL_32,
18969546ca59SPeter Maydell         NULL,
18979546ca59SPeter Maydell     };
18989546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
18999546ca59SPeter Maydell         NULL,
19009546ca59SPeter Maydell         gen_VQDMLAL_acc_16,
19019546ca59SPeter Maydell         gen_VQDMLAL_acc_32,
19029546ca59SPeter Maydell         NULL,
19039546ca59SPeter Maydell     };
19049546ca59SPeter Maydell 
19059546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
19069546ca59SPeter Maydell }
19079546ca59SPeter Maydell 
gen_VQDMLSL_acc_16(TCGv_i64 rd,TCGv_i64 rn,TCGv_i64 rm)19089546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
19099546ca59SPeter Maydell {
19109546ca59SPeter Maydell     gen_helper_neon_negl_u32(rm, rm);
1911ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm);
19129546ca59SPeter Maydell }
19139546ca59SPeter Maydell 
gen_VQDMLSL_acc_32(TCGv_i64 rd,TCGv_i64 rn,TCGv_i64 rm)19149546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm)
19159546ca59SPeter Maydell {
19169546ca59SPeter Maydell     tcg_gen_neg_i64(rm, rm);
1917ad75a51eSRichard Henderson     gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm);
19189546ca59SPeter Maydell }
19199546ca59SPeter Maydell 
trans_VQDMLSL_3d(DisasContext * s,arg_3diff * a)19209546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a)
19219546ca59SPeter Maydell {
19229546ca59SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
19239546ca59SPeter Maydell         NULL,
19249546ca59SPeter Maydell         gen_VQDMULL_16,
19259546ca59SPeter Maydell         gen_VQDMULL_32,
19269546ca59SPeter Maydell         NULL,
19279546ca59SPeter Maydell     };
19289546ca59SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
19299546ca59SPeter Maydell         NULL,
19309546ca59SPeter Maydell         gen_VQDMLSL_acc_16,
19319546ca59SPeter Maydell         gen_VQDMLSL_acc_32,
19329546ca59SPeter Maydell         NULL,
19339546ca59SPeter Maydell     };
19349546ca59SPeter Maydell 
19359546ca59SPeter Maydell     return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
19369546ca59SPeter Maydell }
193718fb58d5SPeter Maydell 
trans_VMULL_P_3d(DisasContext * s,arg_3diff * a)193818fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
193918fb58d5SPeter Maydell {
194018fb58d5SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
194118fb58d5SPeter Maydell 
194218fb58d5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
194318fb58d5SPeter Maydell         return false;
194418fb58d5SPeter Maydell     }
194518fb58d5SPeter Maydell 
194618fb58d5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
194718fb58d5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
194818fb58d5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
194918fb58d5SPeter Maydell         return false;
195018fb58d5SPeter Maydell     }
195118fb58d5SPeter Maydell 
195218fb58d5SPeter Maydell     if (a->vd & 1) {
195318fb58d5SPeter Maydell         return false;
195418fb58d5SPeter Maydell     }
195518fb58d5SPeter Maydell 
195618fb58d5SPeter Maydell     switch (a->size) {
195718fb58d5SPeter Maydell     case 0:
195818fb58d5SPeter Maydell         fn_gvec = gen_helper_neon_pmull_h;
195918fb58d5SPeter Maydell         break;
196018fb58d5SPeter Maydell     case 2:
196118fb58d5SPeter Maydell         if (!dc_isar_feature(aa32_pmull, s)) {
196218fb58d5SPeter Maydell             return false;
196318fb58d5SPeter Maydell         }
196418fb58d5SPeter Maydell         fn_gvec = gen_helper_gvec_pmull_q;
196518fb58d5SPeter Maydell         break;
196618fb58d5SPeter Maydell     default:
196718fb58d5SPeter Maydell         return false;
196818fb58d5SPeter Maydell     }
196918fb58d5SPeter Maydell 
197018fb58d5SPeter Maydell     if (!vfp_access_check(s)) {
197118fb58d5SPeter Maydell         return true;
197218fb58d5SPeter Maydell     }
197318fb58d5SPeter Maydell 
1974015ee81aSRichard Henderson     tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd),
1975015ee81aSRichard Henderson                        neon_full_reg_offset(a->vn),
1976015ee81aSRichard Henderson                        neon_full_reg_offset(a->vm),
197718fb58d5SPeter Maydell                        16, 16, 0, fn_gvec);
197818fb58d5SPeter Maydell     return true;
197918fb58d5SPeter Maydell }
198096fc80f5SPeter Maydell 
gen_neon_dup_low16(TCGv_i32 var)198196fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var)
198296fc80f5SPeter Maydell {
198396fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
198496fc80f5SPeter Maydell     tcg_gen_ext16u_i32(var, var);
198596fc80f5SPeter Maydell     tcg_gen_shli_i32(tmp, var, 16);
198696fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
198796fc80f5SPeter Maydell }
198896fc80f5SPeter Maydell 
gen_neon_dup_high16(TCGv_i32 var)198996fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var)
199096fc80f5SPeter Maydell {
199196fc80f5SPeter Maydell     TCGv_i32 tmp = tcg_temp_new_i32();
199296fc80f5SPeter Maydell     tcg_gen_andi_i32(var, var, 0xffff0000);
199396fc80f5SPeter Maydell     tcg_gen_shri_i32(tmp, var, 16);
199496fc80f5SPeter Maydell     tcg_gen_or_i32(var, var, tmp);
199596fc80f5SPeter Maydell }
199696fc80f5SPeter Maydell 
neon_get_scalar(int size,int reg)199796fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg)
199896fc80f5SPeter Maydell {
1999a712266fSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
2000a712266fSRichard Henderson     if (size == MO_16) {
2001a712266fSRichard Henderson         read_neon_element32(tmp, reg & 7, reg >> 4, MO_32);
200296fc80f5SPeter Maydell         if (reg & 8) {
200396fc80f5SPeter Maydell             gen_neon_dup_high16(tmp);
200496fc80f5SPeter Maydell         } else {
200596fc80f5SPeter Maydell             gen_neon_dup_low16(tmp);
200696fc80f5SPeter Maydell         }
200796fc80f5SPeter Maydell     } else {
2008a712266fSRichard Henderson         read_neon_element32(tmp, reg & 15, reg >> 4, MO_32);
200996fc80f5SPeter Maydell     }
201096fc80f5SPeter Maydell     return tmp;
201196fc80f5SPeter Maydell }
201296fc80f5SPeter Maydell 
do_2scalar(DisasContext * s,arg_2scalar * a,NeonGenTwoOpFn * opfn,NeonGenTwoOpFn * accfn)201396fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a,
201496fc80f5SPeter Maydell                        NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn)
201596fc80f5SPeter Maydell {
201696fc80f5SPeter Maydell     /*
201796fc80f5SPeter Maydell      * Two registers and a scalar: perform an operation between
201896fc80f5SPeter Maydell      * the input elements and the scalar, and then possibly
201996fc80f5SPeter Maydell      * perform an accumulation operation of that result into the
202096fc80f5SPeter Maydell      * destination.
202196fc80f5SPeter Maydell      */
2022a712266fSRichard Henderson     TCGv_i32 scalar, tmp;
202396fc80f5SPeter Maydell     int pass;
202496fc80f5SPeter Maydell 
202596fc80f5SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
202696fc80f5SPeter Maydell         return false;
202796fc80f5SPeter Maydell     }
202896fc80f5SPeter Maydell 
202996fc80f5SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
203096fc80f5SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
203196fc80f5SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
203296fc80f5SPeter Maydell         return false;
203396fc80f5SPeter Maydell     }
203496fc80f5SPeter Maydell 
203596fc80f5SPeter Maydell     if (!opfn) {
203696fc80f5SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
203796fc80f5SPeter Maydell         return false;
203896fc80f5SPeter Maydell     }
203996fc80f5SPeter Maydell 
204096fc80f5SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
204196fc80f5SPeter Maydell         return false;
204296fc80f5SPeter Maydell     }
204396fc80f5SPeter Maydell 
204496fc80f5SPeter Maydell     if (!vfp_access_check(s)) {
204596fc80f5SPeter Maydell         return true;
204696fc80f5SPeter Maydell     }
204796fc80f5SPeter Maydell 
204896fc80f5SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2049a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
205096fc80f5SPeter Maydell 
205196fc80f5SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2052a712266fSRichard Henderson         read_neon_element32(tmp, a->vn, pass, MO_32);
205396fc80f5SPeter Maydell         opfn(tmp, tmp, scalar);
205496fc80f5SPeter Maydell         if (accfn) {
2055a712266fSRichard Henderson             TCGv_i32 rd = tcg_temp_new_i32();
2056a712266fSRichard Henderson             read_neon_element32(rd, a->vd, pass, MO_32);
205796fc80f5SPeter Maydell             accfn(tmp, rd, tmp);
205896fc80f5SPeter Maydell         }
2059a712266fSRichard Henderson         write_neon_element32(tmp, a->vd, pass, MO_32);
206096fc80f5SPeter Maydell     }
206196fc80f5SPeter Maydell     return true;
206296fc80f5SPeter Maydell }
206396fc80f5SPeter Maydell 
trans_VMUL_2sc(DisasContext * s,arg_2scalar * a)206496fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a)
206596fc80f5SPeter Maydell {
206696fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
206796fc80f5SPeter Maydell         NULL,
206896fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
206996fc80f5SPeter Maydell         tcg_gen_mul_i32,
207096fc80f5SPeter Maydell         NULL,
207196fc80f5SPeter Maydell     };
207296fc80f5SPeter Maydell 
207396fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
207496fc80f5SPeter Maydell }
207596fc80f5SPeter Maydell 
trans_VMLA_2sc(DisasContext * s,arg_2scalar * a)207696fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a)
207796fc80f5SPeter Maydell {
207896fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
207996fc80f5SPeter Maydell         NULL,
208096fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
208196fc80f5SPeter Maydell         tcg_gen_mul_i32,
208296fc80f5SPeter Maydell         NULL,
208396fc80f5SPeter Maydell     };
208496fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
208596fc80f5SPeter Maydell         NULL,
208696fc80f5SPeter Maydell         gen_helper_neon_add_u16,
208796fc80f5SPeter Maydell         tcg_gen_add_i32,
208896fc80f5SPeter Maydell         NULL,
208996fc80f5SPeter Maydell     };
209096fc80f5SPeter Maydell 
209196fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
209296fc80f5SPeter Maydell }
209396fc80f5SPeter Maydell 
trans_VMLS_2sc(DisasContext * s,arg_2scalar * a)209496fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a)
209596fc80f5SPeter Maydell {
209696fc80f5SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
209796fc80f5SPeter Maydell         NULL,
209896fc80f5SPeter Maydell         gen_helper_neon_mul_u16,
209996fc80f5SPeter Maydell         tcg_gen_mul_i32,
210096fc80f5SPeter Maydell         NULL,
210196fc80f5SPeter Maydell     };
210296fc80f5SPeter Maydell     static NeonGenTwoOpFn * const accfn[] = {
210396fc80f5SPeter Maydell         NULL,
210496fc80f5SPeter Maydell         gen_helper_neon_sub_u16,
210596fc80f5SPeter Maydell         tcg_gen_sub_i32,
210696fc80f5SPeter Maydell         NULL,
210796fc80f5SPeter Maydell     };
210896fc80f5SPeter Maydell 
210996fc80f5SPeter Maydell     return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
211096fc80f5SPeter Maydell }
211185ac9aefSPeter Maydell 
do_2scalar_fp_vec(DisasContext * s,arg_2scalar * a,gen_helper_gvec_3_ptr * fn)2112fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a,
2113fc8ae790SPeter Maydell                               gen_helper_gvec_3_ptr *fn)
2114fc8ae790SPeter Maydell {
2115fc8ae790SPeter Maydell     /* Two registers and a scalar, using gvec */
2116fc8ae790SPeter Maydell     int vec_size = a->q ? 16 : 8;
2117015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
2118015ee81aSRichard Henderson     int rn_ofs = neon_full_reg_offset(a->vn);
2119fc8ae790SPeter Maydell     int rm_ofs;
2120fc8ae790SPeter Maydell     int idx;
2121fc8ae790SPeter Maydell     TCGv_ptr fpstatus;
2122fc8ae790SPeter Maydell 
2123fc8ae790SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2124fc8ae790SPeter Maydell         return false;
2125fc8ae790SPeter Maydell     }
2126fc8ae790SPeter Maydell 
2127fc8ae790SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2128fc8ae790SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2129fc8ae790SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2130fc8ae790SPeter Maydell         return false;
2131fc8ae790SPeter Maydell     }
2132fc8ae790SPeter Maydell 
2133fc8ae790SPeter Maydell     if (!fn) {
2134fc8ae790SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2135fc8ae790SPeter Maydell         return false;
2136fc8ae790SPeter Maydell     }
2137fc8ae790SPeter Maydell 
2138fc8ae790SPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2139fc8ae790SPeter Maydell         return false;
2140fc8ae790SPeter Maydell     }
2141fc8ae790SPeter Maydell 
2142fc8ae790SPeter Maydell     if (!vfp_access_check(s)) {
2143fc8ae790SPeter Maydell         return true;
2144fc8ae790SPeter Maydell     }
2145fc8ae790SPeter Maydell 
2146fc8ae790SPeter Maydell     /* a->vm is M:Vm, which encodes both register and index */
2147fc8ae790SPeter Maydell     idx = extract32(a->vm, a->size + 2, 2);
2148fc8ae790SPeter Maydell     a->vm = extract32(a->vm, 0, a->size + 2);
2149015ee81aSRichard Henderson     rm_ofs = neon_full_reg_offset(a->vm);
2150fc8ae790SPeter Maydell 
2151fc8ae790SPeter Maydell     fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD);
2152fc8ae790SPeter Maydell     tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus,
2153fc8ae790SPeter Maydell                        vec_size, vec_size, idx, fn);
2154fc8ae790SPeter Maydell     return true;
2155fc8ae790SPeter Maydell }
2156fc8ae790SPeter Maydell 
2157fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC)                                       \
2158fc8ae790SPeter Maydell     static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a)   \
215985ac9aefSPeter Maydell     {                                                                   \
2160fc8ae790SPeter Maydell         static gen_helper_gvec_3_ptr * const opfn[] = {                 \
2161fc8ae790SPeter Maydell             NULL,                                                       \
2162fc8ae790SPeter Maydell             gen_helper_##FUNC##_h,                                      \
2163fc8ae790SPeter Maydell             gen_helper_##FUNC##_s,                                      \
2164fc8ae790SPeter Maydell             NULL,                                                       \
2165fc8ae790SPeter Maydell         };                                                              \
2166fc8ae790SPeter Maydell         if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \
2167fc8ae790SPeter Maydell             return false;                                               \
2168fc8ae790SPeter Maydell         }                                                               \
2169fc8ae790SPeter Maydell         return do_2scalar_fp_vec(s, a, opfn[a->size]);                  \
217085ac9aefSPeter Maydell     }
217185ac9aefSPeter Maydell 
DO_VMUL_F_2sc(VMUL,gvec_fmul_idx)2172fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx)
2173fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx)
2174fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx)
2175b2fc7be9SPeter Maydell 
2176b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
2177b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
2178b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16)
2179b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32)
2180b2fc7be9SPeter Maydell 
2181b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a)
2182b2fc7be9SPeter Maydell {
2183b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2184b2fc7be9SPeter Maydell         NULL,
2185b2fc7be9SPeter Maydell         gen_VQDMULH_16,
2186b2fc7be9SPeter Maydell         gen_VQDMULH_32,
2187b2fc7be9SPeter Maydell         NULL,
2188b2fc7be9SPeter Maydell     };
2189b2fc7be9SPeter Maydell 
2190b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2191b2fc7be9SPeter Maydell }
2192b2fc7be9SPeter Maydell 
trans_VQRDMULH_2sc(DisasContext * s,arg_2scalar * a)2193b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a)
2194b2fc7be9SPeter Maydell {
2195b2fc7be9SPeter Maydell     static NeonGenTwoOpFn * const opfn[] = {
2196b2fc7be9SPeter Maydell         NULL,
2197b2fc7be9SPeter Maydell         gen_VQRDMULH_16,
2198b2fc7be9SPeter Maydell         gen_VQRDMULH_32,
2199b2fc7be9SPeter Maydell         NULL,
2200b2fc7be9SPeter Maydell     };
2201b2fc7be9SPeter Maydell 
2202b2fc7be9SPeter Maydell     return do_2scalar(s, a, opfn[a->size], NULL);
2203b2fc7be9SPeter Maydell }
2204aa318f5bSPeter Maydell 
do_vqrdmlah_2sc(DisasContext * s,arg_2scalar * a,NeonGenThreeOpEnvFn * opfn)2205aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a,
2206aa318f5bSPeter Maydell                             NeonGenThreeOpEnvFn *opfn)
2207aa318f5bSPeter Maydell {
2208aa318f5bSPeter Maydell     /*
2209aa318f5bSPeter Maydell      * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn
2210aa318f5bSPeter Maydell      * performs a kind of fused op-then-accumulate using a helper
2211aa318f5bSPeter Maydell      * function that takes all of rd, rn and the scalar at once.
2212aa318f5bSPeter Maydell      */
2213a712266fSRichard Henderson     TCGv_i32 scalar, rn, rd;
2214aa318f5bSPeter Maydell     int pass;
2215aa318f5bSPeter Maydell 
2216aa318f5bSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2217aa318f5bSPeter Maydell         return false;
2218aa318f5bSPeter Maydell     }
2219aa318f5bSPeter Maydell 
2220aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_rdm, s)) {
2221aa318f5bSPeter Maydell         return false;
2222aa318f5bSPeter Maydell     }
2223aa318f5bSPeter Maydell 
2224aa318f5bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2225aa318f5bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2226aa318f5bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
2227aa318f5bSPeter Maydell         return false;
2228aa318f5bSPeter Maydell     }
2229aa318f5bSPeter Maydell 
2230aa318f5bSPeter Maydell     if (!opfn) {
2231aa318f5bSPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
2232aa318f5bSPeter Maydell         return false;
2233aa318f5bSPeter Maydell     }
2234aa318f5bSPeter Maydell 
2235aa318f5bSPeter Maydell     if (a->q && ((a->vd | a->vn) & 1)) {
2236aa318f5bSPeter Maydell         return false;
2237aa318f5bSPeter Maydell     }
2238aa318f5bSPeter Maydell 
2239aa318f5bSPeter Maydell     if (!vfp_access_check(s)) {
2240aa318f5bSPeter Maydell         return true;
2241aa318f5bSPeter Maydell     }
2242aa318f5bSPeter Maydell 
2243aa318f5bSPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
2244a712266fSRichard Henderson     rn = tcg_temp_new_i32();
2245a712266fSRichard Henderson     rd = tcg_temp_new_i32();
2246aa318f5bSPeter Maydell 
2247aa318f5bSPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
2248a712266fSRichard Henderson         read_neon_element32(rn, a->vn, pass, MO_32);
2249a712266fSRichard Henderson         read_neon_element32(rd, a->vd, pass, MO_32);
2250ad75a51eSRichard Henderson         opfn(rd, tcg_env, rn, scalar, rd);
2251a712266fSRichard Henderson         write_neon_element32(rd, a->vd, pass, MO_32);
2252aa318f5bSPeter Maydell     }
2253aa318f5bSPeter Maydell     return true;
2254aa318f5bSPeter Maydell }
2255aa318f5bSPeter Maydell 
trans_VQRDMLAH_2sc(DisasContext * s,arg_2scalar * a)2256aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a)
2257aa318f5bSPeter Maydell {
2258aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2259aa318f5bSPeter Maydell         NULL,
2260aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s16,
2261aa318f5bSPeter Maydell         gen_helper_neon_qrdmlah_s32,
2262aa318f5bSPeter Maydell         NULL,
2263aa318f5bSPeter Maydell     };
2264aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2265aa318f5bSPeter Maydell }
2266aa318f5bSPeter Maydell 
trans_VQRDMLSH_2sc(DisasContext * s,arg_2scalar * a)2267aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a)
2268aa318f5bSPeter Maydell {
2269aa318f5bSPeter Maydell     static NeonGenThreeOpEnvFn *opfn[] = {
2270aa318f5bSPeter Maydell         NULL,
2271aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s16,
2272aa318f5bSPeter Maydell         gen_helper_neon_qrdmlsh_s32,
2273aa318f5bSPeter Maydell         NULL,
2274aa318f5bSPeter Maydell     };
2275aa318f5bSPeter Maydell     return do_vqrdmlah_2sc(s, a, opfn[a->size]);
2276aa318f5bSPeter Maydell }
227777e576a9SPeter Maydell 
do_2scalar_long(DisasContext * s,arg_2scalar * a,NeonGenTwoOpWidenFn * opfn,NeonGenTwo64OpFn * accfn)227877e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a,
227977e576a9SPeter Maydell                             NeonGenTwoOpWidenFn *opfn,
228077e576a9SPeter Maydell                             NeonGenTwo64OpFn *accfn)
228177e576a9SPeter Maydell {
228277e576a9SPeter Maydell     /*
228377e576a9SPeter Maydell      * Two registers and a scalar, long operations: perform an
228477e576a9SPeter Maydell      * operation on the input elements and the scalar which produces
228577e576a9SPeter Maydell      * a double-width result, and then possibly perform an accumulation
228677e576a9SPeter Maydell      * operation of that result into the destination.
228777e576a9SPeter Maydell      */
228877e576a9SPeter Maydell     TCGv_i32 scalar, rn;
228977e576a9SPeter Maydell     TCGv_i64 rn0_64, rn1_64;
229077e576a9SPeter Maydell 
229177e576a9SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
229277e576a9SPeter Maydell         return false;
229377e576a9SPeter Maydell     }
229477e576a9SPeter Maydell 
229577e576a9SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
229677e576a9SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
229777e576a9SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
229877e576a9SPeter Maydell         return false;
229977e576a9SPeter Maydell     }
230077e576a9SPeter Maydell 
230177e576a9SPeter Maydell     if (!opfn) {
230277e576a9SPeter Maydell         /* Bad size (including size == 3, which is a different insn group) */
230377e576a9SPeter Maydell         return false;
230477e576a9SPeter Maydell     }
230577e576a9SPeter Maydell 
230677e576a9SPeter Maydell     if (a->vd & 1) {
230777e576a9SPeter Maydell         return false;
230877e576a9SPeter Maydell     }
230977e576a9SPeter Maydell 
231077e576a9SPeter Maydell     if (!vfp_access_check(s)) {
231177e576a9SPeter Maydell         return true;
231277e576a9SPeter Maydell     }
231377e576a9SPeter Maydell 
231477e576a9SPeter Maydell     scalar = neon_get_scalar(a->size, a->vm);
231577e576a9SPeter Maydell 
231677e576a9SPeter Maydell     /* Load all inputs before writing any outputs, in case of overlap */
2317a712266fSRichard Henderson     rn = tcg_temp_new_i32();
2318a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 0, MO_32);
231977e576a9SPeter Maydell     rn0_64 = tcg_temp_new_i64();
232077e576a9SPeter Maydell     opfn(rn0_64, rn, scalar);
232177e576a9SPeter Maydell 
2322a712266fSRichard Henderson     read_neon_element32(rn, a->vn, 1, MO_32);
232377e576a9SPeter Maydell     rn1_64 = tcg_temp_new_i64();
232477e576a9SPeter Maydell     opfn(rn1_64, rn, scalar);
232577e576a9SPeter Maydell 
232677e576a9SPeter Maydell     if (accfn) {
232777e576a9SPeter Maydell         TCGv_i64 t64 = tcg_temp_new_i64();
23280aa8e700SRichard Henderson         read_neon_element64(t64, a->vd, 0, MO_64);
23299f1a5f93SRichard Henderson         accfn(rn0_64, t64, rn0_64);
23300aa8e700SRichard Henderson         read_neon_element64(t64, a->vd, 1, MO_64);
23319f1a5f93SRichard Henderson         accfn(rn1_64, t64, rn1_64);
23329f1a5f93SRichard Henderson     }
23339f1a5f93SRichard Henderson 
23340aa8e700SRichard Henderson     write_neon_element64(rn0_64, a->vd, 0, MO_64);
23350aa8e700SRichard Henderson     write_neon_element64(rn1_64, a->vd, 1, MO_64);
233677e576a9SPeter Maydell     return true;
233777e576a9SPeter Maydell }
233877e576a9SPeter Maydell 
trans_VMULL_S_2sc(DisasContext * s,arg_2scalar * a)233977e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a)
234077e576a9SPeter Maydell {
234177e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
234277e576a9SPeter Maydell         NULL,
234377e576a9SPeter Maydell         gen_helper_neon_mull_s16,
234477e576a9SPeter Maydell         gen_mull_s32,
234577e576a9SPeter Maydell         NULL,
234677e576a9SPeter Maydell     };
234777e576a9SPeter Maydell 
234877e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
234977e576a9SPeter Maydell }
235077e576a9SPeter Maydell 
trans_VMULL_U_2sc(DisasContext * s,arg_2scalar * a)235177e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a)
235277e576a9SPeter Maydell {
235377e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
235477e576a9SPeter Maydell         NULL,
235577e576a9SPeter Maydell         gen_helper_neon_mull_u16,
235677e576a9SPeter Maydell         gen_mull_u32,
235777e576a9SPeter Maydell         NULL,
235877e576a9SPeter Maydell     };
235977e576a9SPeter Maydell 
236077e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
236177e576a9SPeter Maydell }
236277e576a9SPeter Maydell 
236377e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC)                                   \
236477e576a9SPeter Maydell     static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a)     \
236577e576a9SPeter Maydell     {                                                                   \
236677e576a9SPeter Maydell         static NeonGenTwoOpWidenFn * const opfn[] = {                   \
236777e576a9SPeter Maydell             NULL,                                                       \
236877e576a9SPeter Maydell             gen_helper_neon_##MULL##16,                                 \
236977e576a9SPeter Maydell             gen_##MULL##32,                                             \
237077e576a9SPeter Maydell             NULL,                                                       \
237177e576a9SPeter Maydell         };                                                              \
237277e576a9SPeter Maydell         static NeonGenTwo64OpFn * const accfn[] = {                     \
237377e576a9SPeter Maydell             NULL,                                                       \
237407e0d7a0SRichard Henderson             tcg_gen_vec_##ACC##32_i64,                                  \
237577e576a9SPeter Maydell             tcg_gen_##ACC##_i64,                                        \
237677e576a9SPeter Maydell             NULL,                                                       \
237777e576a9SPeter Maydell         };                                                              \
237877e576a9SPeter Maydell         return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);    \
237977e576a9SPeter Maydell     }
238077e576a9SPeter Maydell 
DO_VMLAL_2SC(VMLAL_S,mull_s,add)238177e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add)
238277e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add)
238377e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub)
238477e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub)
238577e576a9SPeter Maydell 
238677e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a)
238777e576a9SPeter Maydell {
238877e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
238977e576a9SPeter Maydell         NULL,
239077e576a9SPeter Maydell         gen_VQDMULL_16,
239177e576a9SPeter Maydell         gen_VQDMULL_32,
239277e576a9SPeter Maydell         NULL,
239377e576a9SPeter Maydell     };
239477e576a9SPeter Maydell 
239577e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], NULL);
239677e576a9SPeter Maydell }
239777e576a9SPeter Maydell 
trans_VQDMLAL_2sc(DisasContext * s,arg_2scalar * a)239877e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a)
239977e576a9SPeter Maydell {
240077e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
240177e576a9SPeter Maydell         NULL,
240277e576a9SPeter Maydell         gen_VQDMULL_16,
240377e576a9SPeter Maydell         gen_VQDMULL_32,
240477e576a9SPeter Maydell         NULL,
240577e576a9SPeter Maydell     };
240677e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
240777e576a9SPeter Maydell         NULL,
240877e576a9SPeter Maydell         gen_VQDMLAL_acc_16,
240977e576a9SPeter Maydell         gen_VQDMLAL_acc_32,
241077e576a9SPeter Maydell         NULL,
241177e576a9SPeter Maydell     };
241277e576a9SPeter Maydell 
241377e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
241477e576a9SPeter Maydell }
241577e576a9SPeter Maydell 
trans_VQDMLSL_2sc(DisasContext * s,arg_2scalar * a)241677e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a)
241777e576a9SPeter Maydell {
241877e576a9SPeter Maydell     static NeonGenTwoOpWidenFn * const opfn[] = {
241977e576a9SPeter Maydell         NULL,
242077e576a9SPeter Maydell         gen_VQDMULL_16,
242177e576a9SPeter Maydell         gen_VQDMULL_32,
242277e576a9SPeter Maydell         NULL,
242377e576a9SPeter Maydell     };
242477e576a9SPeter Maydell     static NeonGenTwo64OpFn * const accfn[] = {
242577e576a9SPeter Maydell         NULL,
242677e576a9SPeter Maydell         gen_VQDMLSL_acc_16,
242777e576a9SPeter Maydell         gen_VQDMLSL_acc_32,
242877e576a9SPeter Maydell         NULL,
242977e576a9SPeter Maydell     };
243077e576a9SPeter Maydell 
243177e576a9SPeter Maydell     return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]);
243277e576a9SPeter Maydell }
24330aad761fSPeter Maydell 
trans_VEXT(DisasContext * s,arg_VEXT * a)24340aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a)
24350aad761fSPeter Maydell {
24360aad761fSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
24370aad761fSPeter Maydell         return false;
24380aad761fSPeter Maydell     }
24390aad761fSPeter Maydell 
24400aad761fSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
24410aad761fSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
24420aad761fSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
24430aad761fSPeter Maydell         return false;
24440aad761fSPeter Maydell     }
24450aad761fSPeter Maydell 
24460aad761fSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
24470aad761fSPeter Maydell         return false;
24480aad761fSPeter Maydell     }
24490aad761fSPeter Maydell 
24500aad761fSPeter Maydell     if (a->imm > 7 && !a->q) {
24510aad761fSPeter Maydell         return false;
24520aad761fSPeter Maydell     }
24530aad761fSPeter Maydell 
24540aad761fSPeter Maydell     if (!vfp_access_check(s)) {
24550aad761fSPeter Maydell         return true;
24560aad761fSPeter Maydell     }
24570aad761fSPeter Maydell 
24580aad761fSPeter Maydell     if (!a->q) {
24590aad761fSPeter Maydell         /* Extract 64 bits from <Vm:Vn> */
24600aad761fSPeter Maydell         TCGv_i64 left, right, dest;
24610aad761fSPeter Maydell 
24620aad761fSPeter Maydell         left = tcg_temp_new_i64();
24630aad761fSPeter Maydell         right = tcg_temp_new_i64();
24640aad761fSPeter Maydell         dest = tcg_temp_new_i64();
24650aad761fSPeter Maydell 
24660aa8e700SRichard Henderson         read_neon_element64(right, a->vn, 0, MO_64);
24670aa8e700SRichard Henderson         read_neon_element64(left, a->vm, 0, MO_64);
24680aad761fSPeter Maydell         tcg_gen_extract2_i64(dest, right, left, a->imm * 8);
24690aa8e700SRichard Henderson         write_neon_element64(dest, a->vd, 0, MO_64);
24700aad761fSPeter Maydell     } else {
24710aad761fSPeter Maydell         /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */
24720aad761fSPeter Maydell         TCGv_i64 left, middle, right, destleft, destright;
24730aad761fSPeter Maydell 
24740aad761fSPeter Maydell         left = tcg_temp_new_i64();
24750aad761fSPeter Maydell         middle = tcg_temp_new_i64();
24760aad761fSPeter Maydell         right = tcg_temp_new_i64();
24770aad761fSPeter Maydell         destleft = tcg_temp_new_i64();
24780aad761fSPeter Maydell         destright = tcg_temp_new_i64();
24790aad761fSPeter Maydell 
24800aad761fSPeter Maydell         if (a->imm < 8) {
24810aa8e700SRichard Henderson             read_neon_element64(right, a->vn, 0, MO_64);
24820aa8e700SRichard Henderson             read_neon_element64(middle, a->vn, 1, MO_64);
24830aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, a->imm * 8);
24840aa8e700SRichard Henderson             read_neon_element64(left, a->vm, 0, MO_64);
24850aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8);
24860aad761fSPeter Maydell         } else {
24870aa8e700SRichard Henderson             read_neon_element64(right, a->vn, 1, MO_64);
24880aa8e700SRichard Henderson             read_neon_element64(middle, a->vm, 0, MO_64);
24890aad761fSPeter Maydell             tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8);
24900aa8e700SRichard Henderson             read_neon_element64(left, a->vm, 1, MO_64);
24910aad761fSPeter Maydell             tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8);
24920aad761fSPeter Maydell         }
24930aad761fSPeter Maydell 
24940aa8e700SRichard Henderson         write_neon_element64(destright, a->vd, 0, MO_64);
24950aa8e700SRichard Henderson         write_neon_element64(destleft, a->vd, 1, MO_64);
24960aad761fSPeter Maydell     }
24970aad761fSPeter Maydell     return true;
24980aad761fSPeter Maydell }
249954e96c74SPeter Maydell 
trans_VTBL(DisasContext * s,arg_VTBL * a)250054e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a)
250154e96c74SPeter Maydell {
2502604cef3eSRichard Henderson     TCGv_i64 val, def;
2503604cef3eSRichard Henderson     TCGv_i32 desc;
250454e96c74SPeter Maydell 
250554e96c74SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
250654e96c74SPeter Maydell         return false;
250754e96c74SPeter Maydell     }
250854e96c74SPeter Maydell 
250954e96c74SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
251054e96c74SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
251154e96c74SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
251254e96c74SPeter Maydell         return false;
251354e96c74SPeter Maydell     }
251454e96c74SPeter Maydell 
2515604cef3eSRichard Henderson     if ((a->vn + a->len + 1) > 32) {
251654e96c74SPeter Maydell         /*
251754e96c74SPeter Maydell          * This is UNPREDICTABLE; we choose to UNDEF to avoid the
251854e96c74SPeter Maydell          * helper function running off the end of the register file.
251954e96c74SPeter Maydell          */
252054e96c74SPeter Maydell         return false;
252154e96c74SPeter Maydell     }
2522a712266fSRichard Henderson 
2523b6c56c8aSPeter Maydell     if (!vfp_access_check(s)) {
2524b6c56c8aSPeter Maydell         return true;
2525b6c56c8aSPeter Maydell     }
2526b6c56c8aSPeter Maydell 
2527d9b47e97SRichard Henderson     desc = tcg_constant_i32((a->vn << 2) | a->len);
2528604cef3eSRichard Henderson     def = tcg_temp_new_i64();
252954e96c74SPeter Maydell     if (a->op) {
2530604cef3eSRichard Henderson         read_neon_element64(def, a->vd, 0, MO_64);
253154e96c74SPeter Maydell     } else {
2532604cef3eSRichard Henderson         tcg_gen_movi_i64(def, 0);
253354e96c74SPeter Maydell     }
2534604cef3eSRichard Henderson     val = tcg_temp_new_i64();
2535604cef3eSRichard Henderson     read_neon_element64(val, a->vm, 0, MO_64);
2536a712266fSRichard Henderson 
2537ad75a51eSRichard Henderson     gen_helper_neon_tbl(val, tcg_env, desc, val, def);
2538604cef3eSRichard Henderson     write_neon_element64(val, a->vd, 0, MO_64);
253954e96c74SPeter Maydell     return true;
254054e96c74SPeter Maydell }
25419aaa23c2SPeter Maydell 
trans_VDUP_scalar(DisasContext * s,arg_VDUP_scalar * a)25429aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
25439aaa23c2SPeter Maydell {
25449aaa23c2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
25459aaa23c2SPeter Maydell         return false;
25469aaa23c2SPeter Maydell     }
25479aaa23c2SPeter Maydell 
25489aaa23c2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
25499aaa23c2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
25509aaa23c2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
25519aaa23c2SPeter Maydell         return false;
25529aaa23c2SPeter Maydell     }
25539aaa23c2SPeter Maydell 
25549aaa23c2SPeter Maydell     if (a->vd & a->q) {
25559aaa23c2SPeter Maydell         return false;
25569aaa23c2SPeter Maydell     }
25579aaa23c2SPeter Maydell 
25589aaa23c2SPeter Maydell     if (!vfp_access_check(s)) {
25599aaa23c2SPeter Maydell         return true;
25609aaa23c2SPeter Maydell     }
25619aaa23c2SPeter Maydell 
2562015ee81aSRichard Henderson     tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd),
25639aaa23c2SPeter Maydell                          neon_element_offset(a->vm, a->index, a->size),
25649aaa23c2SPeter Maydell                          a->q ? 16 : 8, a->q ? 16 : 8);
25659aaa23c2SPeter Maydell     return true;
25669aaa23c2SPeter Maydell }
2567353d2b85SPeter Maydell 
2568567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr);
2569567663a2SPeter Maydell 
do_zip_uzp(DisasContext * s,arg_2misc * a,ZipFn * fn)2570567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
2571567663a2SPeter Maydell                        ZipFn *fn)
2572567663a2SPeter Maydell {
2573567663a2SPeter Maydell     TCGv_ptr pd, pm;
2574567663a2SPeter Maydell 
2575567663a2SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2576567663a2SPeter Maydell         return false;
2577567663a2SPeter Maydell     }
2578567663a2SPeter Maydell 
2579567663a2SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2580567663a2SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2581567663a2SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2582567663a2SPeter Maydell         return false;
2583567663a2SPeter Maydell     }
2584567663a2SPeter Maydell 
2585567663a2SPeter Maydell     if ((a->vd | a->vm) & a->q) {
2586567663a2SPeter Maydell         return false;
2587567663a2SPeter Maydell     }
2588567663a2SPeter Maydell 
2589567663a2SPeter Maydell     if (!fn) {
2590567663a2SPeter Maydell         /* Bad size or size/q combination */
2591567663a2SPeter Maydell         return false;
2592567663a2SPeter Maydell     }
2593567663a2SPeter Maydell 
2594567663a2SPeter Maydell     if (!vfp_access_check(s)) {
2595567663a2SPeter Maydell         return true;
2596567663a2SPeter Maydell     }
2597567663a2SPeter Maydell 
2598567663a2SPeter Maydell     pd = vfp_reg_ptr(true, a->vd);
2599567663a2SPeter Maydell     pm = vfp_reg_ptr(true, a->vm);
2600567663a2SPeter Maydell     fn(pd, pm);
2601567663a2SPeter Maydell     return true;
2602567663a2SPeter Maydell }
2603567663a2SPeter Maydell 
trans_VUZP(DisasContext * s,arg_2misc * a)2604567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a)
2605567663a2SPeter Maydell {
2606567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
2607567663a2SPeter Maydell         {
2608567663a2SPeter Maydell             gen_helper_neon_unzip8,
2609567663a2SPeter Maydell             gen_helper_neon_unzip16,
2610567663a2SPeter Maydell             NULL,
2611567663a2SPeter Maydell             NULL,
2612567663a2SPeter Maydell         }, {
2613567663a2SPeter Maydell             gen_helper_neon_qunzip8,
2614567663a2SPeter Maydell             gen_helper_neon_qunzip16,
2615567663a2SPeter Maydell             gen_helper_neon_qunzip32,
2616567663a2SPeter Maydell             NULL,
2617567663a2SPeter Maydell         }
2618567663a2SPeter Maydell     };
2619567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
2620567663a2SPeter Maydell }
2621567663a2SPeter Maydell 
trans_VZIP(DisasContext * s,arg_2misc * a)2622567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a)
2623567663a2SPeter Maydell {
2624567663a2SPeter Maydell     static ZipFn * const fn[2][4] = {
2625567663a2SPeter Maydell         {
2626567663a2SPeter Maydell             gen_helper_neon_zip8,
2627567663a2SPeter Maydell             gen_helper_neon_zip16,
2628567663a2SPeter Maydell             NULL,
2629567663a2SPeter Maydell             NULL,
2630567663a2SPeter Maydell         }, {
2631567663a2SPeter Maydell             gen_helper_neon_qzip8,
2632567663a2SPeter Maydell             gen_helper_neon_qzip16,
2633567663a2SPeter Maydell             gen_helper_neon_qzip32,
2634567663a2SPeter Maydell             NULL,
2635567663a2SPeter Maydell         }
2636567663a2SPeter Maydell     };
2637567663a2SPeter Maydell     return do_zip_uzp(s, a, fn[a->q][a->size]);
2638567663a2SPeter Maydell }
26393882bdacSPeter Maydell 
do_vmovn(DisasContext * s,arg_2misc * a,NeonGenOne64OpEnvFn * narrowfn)26403882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a,
26413e683f0aSRichard Henderson                      NeonGenOne64OpEnvFn *narrowfn)
26423882bdacSPeter Maydell {
26433e683f0aSRichard Henderson     TCGv_i64 rm, rd0, rd1;
26443882bdacSPeter Maydell 
26453882bdacSPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
26463882bdacSPeter Maydell         return false;
26473882bdacSPeter Maydell     }
26483882bdacSPeter Maydell 
26493882bdacSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
26503882bdacSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
26513882bdacSPeter Maydell         ((a->vd | a->vm) & 0x10)) {
26523882bdacSPeter Maydell         return false;
26533882bdacSPeter Maydell     }
26543882bdacSPeter Maydell 
26553882bdacSPeter Maydell     if (a->vm & 1) {
26563882bdacSPeter Maydell         return false;
26573882bdacSPeter Maydell     }
26583882bdacSPeter Maydell 
26593882bdacSPeter Maydell     if (!narrowfn) {
26603882bdacSPeter Maydell         return false;
26613882bdacSPeter Maydell     }
26623882bdacSPeter Maydell 
26633882bdacSPeter Maydell     if (!vfp_access_check(s)) {
26643882bdacSPeter Maydell         return true;
26653882bdacSPeter Maydell     }
26663882bdacSPeter Maydell 
26673882bdacSPeter Maydell     rm = tcg_temp_new_i64();
26683e683f0aSRichard Henderson     rd0 = tcg_temp_new_i64();
26693e683f0aSRichard Henderson     rd1 = tcg_temp_new_i64();
26703882bdacSPeter Maydell 
26710aa8e700SRichard Henderson     read_neon_element64(rm, a->vm, 0, MO_64);
2672ad75a51eSRichard Henderson     narrowfn(rd0, tcg_env, rm);
26730aa8e700SRichard Henderson     read_neon_element64(rm, a->vm, 1, MO_64);
2674ad75a51eSRichard Henderson     narrowfn(rd1, tcg_env, rm);
26753e683f0aSRichard Henderson     write_neon_element64(rd0, a->vd, 0, MO_32);
26763e683f0aSRichard Henderson     write_neon_element64(rd1, a->vd, 1, MO_32);
26773882bdacSPeter Maydell     return true;
26783882bdacSPeter Maydell }
26793882bdacSPeter Maydell 
26803882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC)                                    \
26813882bdacSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
26823882bdacSPeter Maydell     {                                                           \
26833e683f0aSRichard Henderson         static NeonGenOne64OpEnvFn * const narrowfn[] = {       \
26843882bdacSPeter Maydell             FUNC##8,                                            \
26853882bdacSPeter Maydell             FUNC##16,                                           \
26863882bdacSPeter Maydell             FUNC##32,                                           \
26873882bdacSPeter Maydell             NULL,                                               \
26883882bdacSPeter Maydell         };                                                      \
26893882bdacSPeter Maydell         return do_vmovn(s, a, narrowfn[a->size]);               \
26903882bdacSPeter Maydell     }
26913882bdacSPeter Maydell 
DO_VMOVN(VMOVN,gen_neon_narrow_u)26923882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u)
26933882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
26943882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
26953882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
2696749e2be3SPeter Maydell 
2697749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
2698749e2be3SPeter Maydell {
2699749e2be3SPeter Maydell     TCGv_i32 rm0, rm1;
2700749e2be3SPeter Maydell     TCGv_i64 rd;
2701749e2be3SPeter Maydell     static NeonGenWidenFn * const widenfns[] = {
2702749e2be3SPeter Maydell         gen_helper_neon_widen_u8,
2703749e2be3SPeter Maydell         gen_helper_neon_widen_u16,
2704749e2be3SPeter Maydell         tcg_gen_extu_i32_i64,
2705749e2be3SPeter Maydell         NULL,
2706749e2be3SPeter Maydell     };
2707749e2be3SPeter Maydell     NeonGenWidenFn *widenfn = widenfns[a->size];
2708749e2be3SPeter Maydell 
2709749e2be3SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
2710749e2be3SPeter Maydell         return false;
2711749e2be3SPeter Maydell     }
2712749e2be3SPeter Maydell 
2713749e2be3SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2714749e2be3SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2715749e2be3SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2716749e2be3SPeter Maydell         return false;
2717749e2be3SPeter Maydell     }
2718749e2be3SPeter Maydell 
2719749e2be3SPeter Maydell     if (a->vd & 1) {
2720749e2be3SPeter Maydell         return false;
2721749e2be3SPeter Maydell     }
2722749e2be3SPeter Maydell 
2723749e2be3SPeter Maydell     if (!widenfn) {
2724749e2be3SPeter Maydell         return false;
2725749e2be3SPeter Maydell     }
2726749e2be3SPeter Maydell 
2727749e2be3SPeter Maydell     if (!vfp_access_check(s)) {
2728749e2be3SPeter Maydell         return true;
2729749e2be3SPeter Maydell     }
2730749e2be3SPeter Maydell 
2731749e2be3SPeter Maydell     rd = tcg_temp_new_i64();
2732a712266fSRichard Henderson     rm0 = tcg_temp_new_i32();
2733a712266fSRichard Henderson     rm1 = tcg_temp_new_i32();
2734749e2be3SPeter Maydell 
2735a712266fSRichard Henderson     read_neon_element32(rm0, a->vm, 0, MO_32);
2736a712266fSRichard Henderson     read_neon_element32(rm1, a->vm, 1, MO_32);
2737749e2be3SPeter Maydell 
2738749e2be3SPeter Maydell     widenfn(rd, rm0);
2739749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
27400aa8e700SRichard Henderson     write_neon_element64(rd, a->vd, 0, MO_64);
2741749e2be3SPeter Maydell     widenfn(rd, rm1);
2742749e2be3SPeter Maydell     tcg_gen_shli_i64(rd, rd, 8 << a->size);
27430aa8e700SRichard Henderson     write_neon_element64(rd, a->vd, 1, MO_64);
2744749e2be3SPeter Maydell     return true;
2745749e2be3SPeter Maydell }
2746654a5173SPeter Maydell 
trans_VCVT_B16_F32(DisasContext * s,arg_2misc * a)2747d29b17caSRichard Henderson static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a)
2748d29b17caSRichard Henderson {
2749d29b17caSRichard Henderson     TCGv_ptr fpst;
2750d29b17caSRichard Henderson     TCGv_i64 tmp;
2751d29b17caSRichard Henderson     TCGv_i32 dst0, dst1;
2752d29b17caSRichard Henderson 
2753d29b17caSRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
2754d29b17caSRichard Henderson         return false;
2755d29b17caSRichard Henderson     }
2756d29b17caSRichard Henderson 
2757d29b17caSRichard Henderson     /* UNDEF accesses to D16-D31 if they don't exist. */
2758d29b17caSRichard Henderson     if (!dc_isar_feature(aa32_simd_r32, s) &&
2759d29b17caSRichard Henderson         ((a->vd | a->vm) & 0x10)) {
2760d29b17caSRichard Henderson         return false;
2761d29b17caSRichard Henderson     }
2762d29b17caSRichard Henderson 
2763d29b17caSRichard Henderson     if ((a->vm & 1) || (a->size != 1)) {
2764d29b17caSRichard Henderson         return false;
2765d29b17caSRichard Henderson     }
2766d29b17caSRichard Henderson 
2767d29b17caSRichard Henderson     if (!vfp_access_check(s)) {
2768d29b17caSRichard Henderson         return true;
2769d29b17caSRichard Henderson     }
2770d29b17caSRichard Henderson 
2771d29b17caSRichard Henderson     fpst = fpstatus_ptr(FPST_STD);
2772d29b17caSRichard Henderson     tmp = tcg_temp_new_i64();
2773d29b17caSRichard Henderson     dst0 = tcg_temp_new_i32();
2774d29b17caSRichard Henderson     dst1 = tcg_temp_new_i32();
2775d29b17caSRichard Henderson 
2776d29b17caSRichard Henderson     read_neon_element64(tmp, a->vm, 0, MO_64);
2777d29b17caSRichard Henderson     gen_helper_bfcvt_pair(dst0, tmp, fpst);
2778d29b17caSRichard Henderson 
2779d29b17caSRichard Henderson     read_neon_element64(tmp, a->vm, 1, MO_64);
2780d29b17caSRichard Henderson     gen_helper_bfcvt_pair(dst1, tmp, fpst);
2781d29b17caSRichard Henderson 
2782d29b17caSRichard Henderson     write_neon_element32(dst0, a->vd, 0, MO_32);
2783d29b17caSRichard Henderson     write_neon_element32(dst1, a->vd, 1, MO_32);
2784d29b17caSRichard Henderson     return true;
2785d29b17caSRichard Henderson }
2786d29b17caSRichard Henderson 
trans_VCVT_F16_F32(DisasContext * s,arg_2misc * a)2787654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
2788654a5173SPeter Maydell {
2789654a5173SPeter Maydell     TCGv_ptr fpst;
2790654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
2791654a5173SPeter Maydell 
2792654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
2793654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
2794654a5173SPeter Maydell         return false;
2795654a5173SPeter Maydell     }
2796654a5173SPeter Maydell 
2797654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2798654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2799654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2800654a5173SPeter Maydell         return false;
2801654a5173SPeter Maydell     }
2802654a5173SPeter Maydell 
2803654a5173SPeter Maydell     if ((a->vm & 1) || (a->size != 1)) {
2804654a5173SPeter Maydell         return false;
2805654a5173SPeter Maydell     }
2806654a5173SPeter Maydell 
2807654a5173SPeter Maydell     if (!vfp_access_check(s)) {
2808654a5173SPeter Maydell         return true;
2809654a5173SPeter Maydell     }
2810654a5173SPeter Maydell 
2811a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
2812654a5173SPeter Maydell     ahp = get_ahp_flag();
2813a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
2814a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 0, MO_32);
2815654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
2816a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
2817a712266fSRichard Henderson     read_neon_element32(tmp2, a->vm, 1, MO_32);
2818654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
2819654a5173SPeter Maydell     tcg_gen_shli_i32(tmp2, tmp2, 16);
2820654a5173SPeter Maydell     tcg_gen_or_i32(tmp2, tmp2, tmp);
2821a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 2, MO_32);
2822654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
2823a712266fSRichard Henderson     tmp3 = tcg_temp_new_i32();
2824a712266fSRichard Henderson     read_neon_element32(tmp3, a->vm, 3, MO_32);
2825a712266fSRichard Henderson     write_neon_element32(tmp2, a->vd, 0, MO_32);
2826654a5173SPeter Maydell     gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
2827654a5173SPeter Maydell     tcg_gen_shli_i32(tmp3, tmp3, 16);
2828654a5173SPeter Maydell     tcg_gen_or_i32(tmp3, tmp3, tmp);
2829a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 1, MO_32);
2830654a5173SPeter Maydell     return true;
2831654a5173SPeter Maydell }
2832654a5173SPeter Maydell 
trans_VCVT_F32_F16(DisasContext * s,arg_2misc * a)2833654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
2834654a5173SPeter Maydell {
2835654a5173SPeter Maydell     TCGv_ptr fpst;
2836654a5173SPeter Maydell     TCGv_i32 ahp, tmp, tmp2, tmp3;
2837654a5173SPeter Maydell 
2838654a5173SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
2839654a5173SPeter Maydell         !dc_isar_feature(aa32_fp16_spconv, s)) {
2840654a5173SPeter Maydell         return false;
2841654a5173SPeter Maydell     }
2842654a5173SPeter Maydell 
2843654a5173SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
2844654a5173SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
2845654a5173SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
2846654a5173SPeter Maydell         return false;
2847654a5173SPeter Maydell     }
2848654a5173SPeter Maydell 
2849654a5173SPeter Maydell     if ((a->vd & 1) || (a->size != 1)) {
2850654a5173SPeter Maydell         return false;
2851654a5173SPeter Maydell     }
2852654a5173SPeter Maydell 
2853654a5173SPeter Maydell     if (!vfp_access_check(s)) {
2854654a5173SPeter Maydell         return true;
2855654a5173SPeter Maydell     }
2856654a5173SPeter Maydell 
2857a84d1d13SPeter Maydell     fpst = fpstatus_ptr(FPST_STD);
2858654a5173SPeter Maydell     ahp = get_ahp_flag();
2859654a5173SPeter Maydell     tmp3 = tcg_temp_new_i32();
2860a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
2861a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
2862a712266fSRichard Henderson     read_neon_element32(tmp, a->vm, 0, MO_32);
2863a712266fSRichard Henderson     read_neon_element32(tmp2, a->vm, 1, MO_32);
2864654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp);
2865654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
2866a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 0, MO_32);
2867654a5173SPeter Maydell     tcg_gen_shri_i32(tmp, tmp, 16);
2868654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
2869a712266fSRichard Henderson     write_neon_element32(tmp, a->vd, 1, MO_32);
2870654a5173SPeter Maydell     tcg_gen_ext16u_i32(tmp3, tmp2);
2871654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
2872a712266fSRichard Henderson     write_neon_element32(tmp3, a->vd, 2, MO_32);
2873654a5173SPeter Maydell     tcg_gen_shri_i32(tmp2, tmp2, 16);
2874654a5173SPeter Maydell     gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
2875a712266fSRichard Henderson     write_neon_element32(tmp2, a->vd, 3, MO_32);
2876654a5173SPeter Maydell     return true;
2877654a5173SPeter Maydell }
287875153179SPeter Maydell 
do_2misc_vec(DisasContext * s,arg_2misc * a,GVecGen2Fn * fn)287975153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
288075153179SPeter Maydell {
288175153179SPeter Maydell     int vec_size = a->q ? 16 : 8;
2882015ee81aSRichard Henderson     int rd_ofs = neon_full_reg_offset(a->vd);
2883015ee81aSRichard Henderson     int rm_ofs = neon_full_reg_offset(a->vm);
288475153179SPeter Maydell 
288575153179SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
288675153179SPeter Maydell         return false;
288775153179SPeter Maydell     }
288875153179SPeter Maydell 
288975153179SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
289075153179SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
289175153179SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
289275153179SPeter Maydell         return false;
289375153179SPeter Maydell     }
289475153179SPeter Maydell 
289575153179SPeter Maydell     if (a->size == 3) {
289675153179SPeter Maydell         return false;
289775153179SPeter Maydell     }
289875153179SPeter Maydell 
289975153179SPeter Maydell     if ((a->vd | a->vm) & a->q) {
290075153179SPeter Maydell         return false;
290175153179SPeter Maydell     }
290275153179SPeter Maydell 
290375153179SPeter Maydell     if (!vfp_access_check(s)) {
290475153179SPeter Maydell         return true;
290575153179SPeter Maydell     }
290675153179SPeter Maydell 
290775153179SPeter Maydell     fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size);
290875153179SPeter Maydell 
290975153179SPeter Maydell     return true;
291075153179SPeter Maydell }
291175153179SPeter Maydell 
291275153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN)                                  \
291375153179SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
291475153179SPeter Maydell     {                                                           \
291575153179SPeter Maydell         return do_2misc_vec(s, a, FN);                          \
291675153179SPeter Maydell     }
291775153179SPeter Maydell 
DO_2MISC_VEC(VNEG,tcg_gen_gvec_neg)291875153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg)
291975153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs)
292075153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0)
292175153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
292275153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
292375153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
292475153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
29254fedfb48SRichard Henderson DO_2MISC_VEC(VCLS, gen_gvec_cls)
29264fedfb48SRichard Henderson DO_2MISC_VEC(VCLZ, gen_gvec_clz)
292738f9950cSRichard Henderson DO_2MISC_VEC(VREV64, gen_gvec_rev64)
2928c14bde69SRichard Henderson DO_2MISC_VEC(VPADDL_S, gen_gvec_saddlp)
2929c14bde69SRichard Henderson DO_2MISC_VEC(VPADDL_U, gen_gvec_uaddlp)
2930c14bde69SRichard Henderson DO_2MISC_VEC(VPADAL_S, gen_gvec_sadalp)
2931c14bde69SRichard Henderson DO_2MISC_VEC(VPADAL_U, gen_gvec_uadalp)
293275153179SPeter Maydell 
293375153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a)
293475153179SPeter Maydell {
293575153179SPeter Maydell     if (a->size != 0) {
293675153179SPeter Maydell         return false;
293775153179SPeter Maydell     }
293875153179SPeter Maydell     return do_2misc_vec(s, a, tcg_gen_gvec_not);
293975153179SPeter Maydell }
29400b30dd5bSPeter Maydell 
trans_VCNT(DisasContext * s,arg_2misc * a)29414694d574SRichard Henderson static bool trans_VCNT(DisasContext *s, arg_2misc *a)
29424694d574SRichard Henderson {
29434694d574SRichard Henderson     if (a->size != 0) {
29444694d574SRichard Henderson         return false;
29454694d574SRichard Henderson     }
29464694d574SRichard Henderson     return do_2misc_vec(s, a, gen_gvec_cnt);
29474694d574SRichard Henderson }
29484694d574SRichard Henderson 
trans_VREV16(DisasContext * s,arg_2misc * a)294938f9950cSRichard Henderson static bool trans_VREV16(DisasContext *s, arg_2misc *a)
295038f9950cSRichard Henderson {
295138f9950cSRichard Henderson     if (a->size != 0) {
295238f9950cSRichard Henderson         return false;
295338f9950cSRichard Henderson     }
295438f9950cSRichard Henderson     return do_2misc_vec(s, a, gen_gvec_rev16);
295538f9950cSRichard Henderson }
295638f9950cSRichard Henderson 
trans_VREV32(DisasContext * s,arg_2misc * a)295738f9950cSRichard Henderson static bool trans_VREV32(DisasContext *s, arg_2misc *a)
295838f9950cSRichard Henderson {
295938f9950cSRichard Henderson     if (a->size != 0 && a->size != 1) {
296038f9950cSRichard Henderson         return false;
296138f9950cSRichard Henderson     }
296238f9950cSRichard Henderson     return do_2misc_vec(s, a, gen_gvec_rev32);
296338f9950cSRichard Henderson }
296438f9950cSRichard Henderson 
29650b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA)                          \
29660b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
29670b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
29680b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
29690b30dd5bSPeter Maydell     {                                                                   \
29700b30dd5bSPeter Maydell         tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz,        \
29710b30dd5bSPeter Maydell                            DATA, FUNC);                                 \
29720b30dd5bSPeter Maydell     }
29730b30dd5bSPeter Maydell 
29740b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA)                          \
29750b30dd5bSPeter Maydell     static void WRAPNAME(unsigned vece, uint32_t rd_ofs,                \
29760b30dd5bSPeter Maydell                          uint32_t rm_ofs, uint32_t oprsz,               \
29770b30dd5bSPeter Maydell                          uint32_t maxsz)                                \
29780b30dd5bSPeter Maydell     {                                                                   \
29790b30dd5bSPeter Maydell         tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC);   \
29800b30dd5bSPeter Maydell     }
29810b30dd5bSPeter Maydell 
29820b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0)
29830f23908cSRichard Henderson WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aesd, 0)
29840b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0)
29850f23908cSRichard Henderson WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesimc, 0)
29860b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0)
29870b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0)
29880b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0)
29890b30dd5bSPeter Maydell 
29900b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE)                       \
29910b30dd5bSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)     \
29920b30dd5bSPeter Maydell     {                                                           \
29930b30dd5bSPeter Maydell         if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) {  \
29940b30dd5bSPeter Maydell             return false;                                       \
29950b30dd5bSPeter Maydell         }                                                       \
29960b30dd5bSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                  \
29970b30dd5bSPeter Maydell     }
29980b30dd5bSPeter Maydell 
29990b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0)
30000b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0)
30010b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0)
30020b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
30030b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
30040b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
30050b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
300689668082SPeter Maydell 
do_2misc(DisasContext * s,arg_2misc * a,NeonGenOneOpFn * fn)300789668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
300889668082SPeter Maydell {
3009a712266fSRichard Henderson     TCGv_i32 tmp;
301089668082SPeter Maydell     int pass;
301189668082SPeter Maydell 
301289668082SPeter Maydell     /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
301389668082SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
301489668082SPeter Maydell         return false;
301589668082SPeter Maydell     }
301689668082SPeter Maydell 
301789668082SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
301889668082SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
301989668082SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
302089668082SPeter Maydell         return false;
302189668082SPeter Maydell     }
302289668082SPeter Maydell 
302389668082SPeter Maydell     if (!fn) {
302489668082SPeter Maydell         return false;
302589668082SPeter Maydell     }
302689668082SPeter Maydell 
302789668082SPeter Maydell     if ((a->vd | a->vm) & a->q) {
302889668082SPeter Maydell         return false;
302989668082SPeter Maydell     }
303089668082SPeter Maydell 
303189668082SPeter Maydell     if (!vfp_access_check(s)) {
303289668082SPeter Maydell         return true;
303389668082SPeter Maydell     }
303489668082SPeter Maydell 
3035a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
303689668082SPeter Maydell     for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
3037a712266fSRichard Henderson         read_neon_element32(tmp, a->vm, pass, MO_32);
303889668082SPeter Maydell         fn(tmp, tmp);
3039a712266fSRichard Henderson         write_neon_element32(tmp, a->vd, pass, MO_32);
304089668082SPeter Maydell     }
304189668082SPeter Maydell     return true;
304289668082SPeter Maydell }
304389668082SPeter Maydell 
trans_VABS_F(DisasContext * s,arg_2misc * a)304484eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
304584eae770SPeter Maydell {
30462b70d8cdSPeter Maydell     if (a->size == MO_16) {
30472b70d8cdSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
304884eae770SPeter Maydell             return false;
304984eae770SPeter Maydell         }
30502b70d8cdSPeter Maydell     } else if (a->size != MO_32) {
30512b70d8cdSPeter Maydell         return false;
30522b70d8cdSPeter Maydell     }
3053f0632d48SRichard Henderson     return do_2misc_vec(s, a, gen_gvec_fabs);
305484eae770SPeter Maydell }
305584eae770SPeter Maydell 
trans_VNEG_F(DisasContext * s,arg_2misc * a)305684eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
305784eae770SPeter Maydell {
30582b70d8cdSPeter Maydell     if (a->size == MO_16) {
30592b70d8cdSPeter Maydell         if (!dc_isar_feature(aa32_fp16_arith, s)) {
306084eae770SPeter Maydell             return false;
306184eae770SPeter Maydell         }
30622b70d8cdSPeter Maydell     } else if (a->size != MO_32) {
30632b70d8cdSPeter Maydell         return false;
30642b70d8cdSPeter Maydell     }
3065f0632d48SRichard Henderson     return do_2misc_vec(s, a, gen_gvec_fneg);
306684eae770SPeter Maydell }
306784eae770SPeter Maydell 
trans_VRECPE(DisasContext * s,arg_2misc * a)306884eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
306984eae770SPeter Maydell {
307084eae770SPeter Maydell     if (a->size != 2) {
307184eae770SPeter Maydell         return false;
307284eae770SPeter Maydell     }
3073*8710a43dSRichard Henderson     return do_2misc_vec(s, a, gen_gvec_urecpe);
307484eae770SPeter Maydell }
307584eae770SPeter Maydell 
trans_VRSQRTE(DisasContext * s,arg_2misc * a)307684eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
307784eae770SPeter Maydell {
307884eae770SPeter Maydell     if (a->size != 2) {
307984eae770SPeter Maydell         return false;
308084eae770SPeter Maydell     }
3081*8710a43dSRichard Henderson     return do_2misc_vec(s, a, gen_gvec_ursqrte);
308284eae770SPeter Maydell }
30834936f38aSPeter Maydell 
30844936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \
30854936f38aSPeter Maydell     static void WRAPNAME(TCGv_i32 d, TCGv_i32 m)        \
30864936f38aSPeter Maydell     {                                                   \
3087ad75a51eSRichard Henderson         FUNC(d, tcg_env, m);                            \
30884936f38aSPeter Maydell     }
30894936f38aSPeter Maydell 
WRAP_1OP_ENV_FN(gen_VQABS_s8,gen_helper_neon_qabs_s8)30904936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8)
30914936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16)
30924936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32)
30934936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8)
30944936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16)
30954936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32)
30964936f38aSPeter Maydell 
30974936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a)
30984936f38aSPeter Maydell {
30994936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
31004936f38aSPeter Maydell         gen_VQABS_s8,
31014936f38aSPeter Maydell         gen_VQABS_s16,
31024936f38aSPeter Maydell         gen_VQABS_s32,
31034936f38aSPeter Maydell         NULL,
31044936f38aSPeter Maydell     };
31054936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
31064936f38aSPeter Maydell }
31074936f38aSPeter Maydell 
trans_VQNEG(DisasContext * s,arg_2misc * a)31084936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a)
31094936f38aSPeter Maydell {
31104936f38aSPeter Maydell     static NeonGenOneOpFn * const fn[] = {
31114936f38aSPeter Maydell         gen_VQNEG_s8,
31124936f38aSPeter Maydell         gen_VQNEG_s16,
31134936f38aSPeter Maydell         gen_VQNEG_s32,
31144936f38aSPeter Maydell         NULL,
31154936f38aSPeter Maydell     };
31164936f38aSPeter Maydell     return do_2misc(s, a, fn[a->size]);
31174936f38aSPeter Maydell }
31183e96b205SPeter Maydell 
31194a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC)                             \
31204a15d9a3SPeter Maydell     static void gen_##INSN(unsigned vece, uint32_t rd_ofs,              \
31214a15d9a3SPeter Maydell                            uint32_t rm_ofs,                             \
31224a15d9a3SPeter Maydell                            uint32_t oprsz, uint32_t maxsz)              \
31234a15d9a3SPeter Maydell     {                                                                   \
31244a15d9a3SPeter Maydell         static gen_helper_gvec_2_ptr * const fns[4] = {                 \
31254a15d9a3SPeter Maydell             NULL, HFUNC, SFUNC, NULL,                                   \
31264a15d9a3SPeter Maydell         };                                                              \
31274a15d9a3SPeter Maydell         TCGv_ptr fpst;                                                  \
31284a15d9a3SPeter Maydell         fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD);   \
31294a15d9a3SPeter Maydell         tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0,       \
31304a15d9a3SPeter Maydell                            fns[vece]);                                  \
31314a15d9a3SPeter Maydell     }                                                                   \
31324a15d9a3SPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)             \
31334a15d9a3SPeter Maydell     {                                                                   \
31344a15d9a3SPeter Maydell         if (a->size == MO_16) {                                         \
31354a15d9a3SPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
31364a15d9a3SPeter Maydell                 return false;                                           \
31374a15d9a3SPeter Maydell             }                                                           \
31384a15d9a3SPeter Maydell         } else if (a->size != MO_32) {                                  \
31394a15d9a3SPeter Maydell             return false;                                               \
31404a15d9a3SPeter Maydell         }                                                               \
31414a15d9a3SPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                          \
31424a15d9a3SPeter Maydell     }
31434a15d9a3SPeter Maydell 
DO_2MISC_FP_VEC(VRECPE_F,gen_helper_gvec_frecpe_h,gen_helper_gvec_frecpe_s)31444a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s)
31454a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s)
3146635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s)
3147635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s)
3148635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s)
3149635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s)
3150635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s)
31517782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos)
31527782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos)
31537782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs)
31547782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs)
31554a15d9a3SPeter Maydell 
315623afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s)
315723afcdd2SPeter Maydell 
31583e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a)
31593e96b205SPeter Maydell {
31603e96b205SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
31613e96b205SPeter Maydell         return false;
31623e96b205SPeter Maydell     }
316323afcdd2SPeter Maydell     return trans_VRINTX_impl(s, a);
31643e96b205SPeter Maydell }
3165baa59323SPeter Maydell 
3166ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP)                                   \
3167ca88a6efSPeter Maydell     static void gen_##INSN(unsigned vece, uint32_t rd_ofs,              \
3168ca88a6efSPeter Maydell                            uint32_t rm_ofs,                             \
3169ca88a6efSPeter Maydell                            uint32_t oprsz, uint32_t maxsz)              \
3170ca88a6efSPeter Maydell     {                                                                   \
3171ca88a6efSPeter Maydell         static gen_helper_gvec_2_ptr * const fns[4] = {                 \
3172ca88a6efSPeter Maydell             NULL,                                                       \
3173ca88a6efSPeter Maydell             gen_helper_gvec_##OP##h,                                    \
3174ca88a6efSPeter Maydell             gen_helper_gvec_##OP##s,                                    \
3175ca88a6efSPeter Maydell             NULL,                                                       \
3176ca88a6efSPeter Maydell         };                                                              \
3177ca88a6efSPeter Maydell         TCGv_ptr fpst;                                                  \
3178ca88a6efSPeter Maydell         fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD);       \
3179ca88a6efSPeter Maydell         tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz,          \
3180ca88a6efSPeter Maydell                            arm_rmode_to_sf(RMODE), fns[vece]);          \
3181ca88a6efSPeter Maydell     }                                                                   \
3182a183d5fbSPeter Maydell     static bool trans_##INSN(DisasContext *s, arg_2misc *a)             \
3183a183d5fbSPeter Maydell     {                                                                   \
3184ca88a6efSPeter Maydell         if (!arm_dc_feature(s, ARM_FEATURE_V8)) {                       \
3185ca88a6efSPeter Maydell             return false;                                               \
3186ca88a6efSPeter Maydell         }                                                               \
3187ca88a6efSPeter Maydell         if (a->size == MO_16) {                                         \
3188ca88a6efSPeter Maydell             if (!dc_isar_feature(aa32_fp16_arith, s)) {                 \
3189ca88a6efSPeter Maydell                 return false;                                           \
3190ca88a6efSPeter Maydell             }                                                           \
3191ca88a6efSPeter Maydell         } else if (a->size != MO_32) {                                  \
3192ca88a6efSPeter Maydell             return false;                                               \
3193ca88a6efSPeter Maydell         }                                                               \
3194ca88a6efSPeter Maydell         return do_2misc_vec(s, a, gen_##INSN);                          \
3195a183d5fbSPeter Maydell     }
3196a183d5fbSPeter Maydell 
DO_VEC_RMODE(VCVTAU,FPROUNDING_TIEAWAY,vcvt_rm_u)3197ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u)
3198ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s)
3199ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u)
3200ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s)
3201ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u)
3202ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s)
3203ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u)
3204ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s)
32058ab3a227SPeter Maydell 
320618725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_)
320718725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_)
320818725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_)
320918725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_)
321018725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_)
321118725916SPeter Maydell 
32128ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a)
32138ab3a227SPeter Maydell {
32148ab3a227SPeter Maydell     TCGv_i64 rm, rd;
32158ab3a227SPeter Maydell     int pass;
32168ab3a227SPeter Maydell 
32178ab3a227SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
32188ab3a227SPeter Maydell         return false;
32198ab3a227SPeter Maydell     }
32208ab3a227SPeter Maydell 
32218ab3a227SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
32228ab3a227SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
32238ab3a227SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
32248ab3a227SPeter Maydell         return false;
32258ab3a227SPeter Maydell     }
32268ab3a227SPeter Maydell 
32278ab3a227SPeter Maydell     if (a->size != 0) {
32288ab3a227SPeter Maydell         return false;
32298ab3a227SPeter Maydell     }
32308ab3a227SPeter Maydell 
32318ab3a227SPeter Maydell     if ((a->vd | a->vm) & a->q) {
32328ab3a227SPeter Maydell         return false;
32338ab3a227SPeter Maydell     }
32348ab3a227SPeter Maydell 
32358ab3a227SPeter Maydell     if (!vfp_access_check(s)) {
32368ab3a227SPeter Maydell         return true;
32378ab3a227SPeter Maydell     }
32388ab3a227SPeter Maydell 
32398ab3a227SPeter Maydell     rm = tcg_temp_new_i64();
32408ab3a227SPeter Maydell     rd = tcg_temp_new_i64();
32418ab3a227SPeter Maydell     for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
32420aa8e700SRichard Henderson         read_neon_element64(rm, a->vm, pass, MO_64);
32430aa8e700SRichard Henderson         read_neon_element64(rd, a->vd, pass, MO_64);
32440aa8e700SRichard Henderson         write_neon_element64(rm, a->vd, pass, MO_64);
32450aa8e700SRichard Henderson         write_neon_element64(rd, a->vm, pass, MO_64);
32468ab3a227SPeter Maydell     }
32478ab3a227SPeter Maydell     return true;
32488ab3a227SPeter Maydell }
324924f4531dSRichard Henderson 
gen_neon_trn_u8(TCGv_i32 t0,TCGv_i32 t1)3250d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
3251d4366190SPeter Maydell {
3252d4366190SPeter Maydell     TCGv_i32 rd, tmp;
3253d4366190SPeter Maydell 
3254d4366190SPeter Maydell     rd = tcg_temp_new_i32();
3255d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
3256d4366190SPeter Maydell 
3257d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 8);
3258d4366190SPeter Maydell     tcg_gen_andi_i32(rd, rd, 0xff00ff00);
3259d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
3260d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
3261d4366190SPeter Maydell 
3262d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 8);
3263d4366190SPeter Maydell     tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
3264d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
3265d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
3266d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
3267d4366190SPeter Maydell }
3268d4366190SPeter Maydell 
gen_neon_trn_u16(TCGv_i32 t0,TCGv_i32 t1)3269d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
3270d4366190SPeter Maydell {
3271d4366190SPeter Maydell     TCGv_i32 rd, tmp;
3272d4366190SPeter Maydell 
3273d4366190SPeter Maydell     rd = tcg_temp_new_i32();
3274d4366190SPeter Maydell     tmp = tcg_temp_new_i32();
3275d4366190SPeter Maydell 
3276d4366190SPeter Maydell     tcg_gen_shli_i32(rd, t0, 16);
3277d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t1, 0xffff);
3278d4366190SPeter Maydell     tcg_gen_or_i32(rd, rd, tmp);
3279d4366190SPeter Maydell     tcg_gen_shri_i32(t1, t1, 16);
3280d4366190SPeter Maydell     tcg_gen_andi_i32(tmp, t0, 0xffff0000);
3281d4366190SPeter Maydell     tcg_gen_or_i32(t1, t1, tmp);
3282d4366190SPeter Maydell     tcg_gen_mov_i32(t0, rd);
3283d4366190SPeter Maydell }
3284d4366190SPeter Maydell 
trans_VTRN(DisasContext * s,arg_2misc * a)3285d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a)
3286d4366190SPeter Maydell {
3287d4366190SPeter Maydell     TCGv_i32 tmp, tmp2;
3288d4366190SPeter Maydell     int pass;
3289d4366190SPeter Maydell 
3290d4366190SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
3291d4366190SPeter Maydell         return false;
3292d4366190SPeter Maydell     }
3293d4366190SPeter Maydell 
3294d4366190SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
3295d4366190SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
3296d4366190SPeter Maydell         ((a->vd | a->vm) & 0x10)) {
3297d4366190SPeter Maydell         return false;
3298d4366190SPeter Maydell     }
3299d4366190SPeter Maydell 
3300d4366190SPeter Maydell     if ((a->vd | a->vm) & a->q) {
3301d4366190SPeter Maydell         return false;
3302d4366190SPeter Maydell     }
3303d4366190SPeter Maydell 
3304d4366190SPeter Maydell     if (a->size == 3) {
3305d4366190SPeter Maydell         return false;
3306d4366190SPeter Maydell     }
3307d4366190SPeter Maydell 
3308d4366190SPeter Maydell     if (!vfp_access_check(s)) {
3309d4366190SPeter Maydell         return true;
3310d4366190SPeter Maydell     }
3311d4366190SPeter Maydell 
3312a712266fSRichard Henderson     tmp = tcg_temp_new_i32();
3313a712266fSRichard Henderson     tmp2 = tcg_temp_new_i32();
3314a712266fSRichard Henderson     if (a->size == MO_32) {
3315d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) {
3316a712266fSRichard Henderson             read_neon_element32(tmp, a->vm, pass, MO_32);
3317a712266fSRichard Henderson             read_neon_element32(tmp2, a->vd, pass + 1, MO_32);
3318a712266fSRichard Henderson             write_neon_element32(tmp2, a->vm, pass, MO_32);
3319a712266fSRichard Henderson             write_neon_element32(tmp, a->vd, pass + 1, MO_32);
3320d4366190SPeter Maydell         }
3321d4366190SPeter Maydell     } else {
3322d4366190SPeter Maydell         for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
3323a712266fSRichard Henderson             read_neon_element32(tmp, a->vm, pass, MO_32);
3324a712266fSRichard Henderson             read_neon_element32(tmp2, a->vd, pass, MO_32);
3325a712266fSRichard Henderson             if (a->size == MO_8) {
3326d4366190SPeter Maydell                 gen_neon_trn_u8(tmp, tmp2);
3327d4366190SPeter Maydell             } else {
3328d4366190SPeter Maydell                 gen_neon_trn_u16(tmp, tmp2);
3329d4366190SPeter Maydell             }
3330a712266fSRichard Henderson             write_neon_element32(tmp2, a->vm, pass, MO_32);
3331a712266fSRichard Henderson             write_neon_element32(tmp, a->vd, pass, MO_32);
3332d4366190SPeter Maydell         }
3333d4366190SPeter Maydell     }
3334d4366190SPeter Maydell     return true;
3335d4366190SPeter Maydell }
33362323c5ffSRichard Henderson 
trans_VSMMLA(DisasContext * s,arg_VSMMLA * a)33372323c5ffSRichard Henderson static bool trans_VSMMLA(DisasContext *s, arg_VSMMLA *a)
33382323c5ffSRichard Henderson {
33392323c5ffSRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
33402323c5ffSRichard Henderson         return false;
33412323c5ffSRichard Henderson     }
33422323c5ffSRichard Henderson     return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0,
33432323c5ffSRichard Henderson                         gen_helper_gvec_smmla_b);
33442323c5ffSRichard Henderson }
33452323c5ffSRichard Henderson 
trans_VUMMLA(DisasContext * s,arg_VUMMLA * a)33462323c5ffSRichard Henderson static bool trans_VUMMLA(DisasContext *s, arg_VUMMLA *a)
33472323c5ffSRichard Henderson {
33482323c5ffSRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
33492323c5ffSRichard Henderson         return false;
33502323c5ffSRichard Henderson     }
33512323c5ffSRichard Henderson     return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0,
33522323c5ffSRichard Henderson                         gen_helper_gvec_ummla_b);
33532323c5ffSRichard Henderson }
33542323c5ffSRichard Henderson 
trans_VUSMMLA(DisasContext * s,arg_VUSMMLA * a)33552323c5ffSRichard Henderson static bool trans_VUSMMLA(DisasContext *s, arg_VUSMMLA *a)
33562323c5ffSRichard Henderson {
33572323c5ffSRichard Henderson     if (!dc_isar_feature(aa32_i8mm, s)) {
33582323c5ffSRichard Henderson         return false;
33592323c5ffSRichard Henderson     }
33602323c5ffSRichard Henderson     return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0,
33612323c5ffSRichard Henderson                         gen_helper_gvec_usmmla_b);
33622323c5ffSRichard Henderson }
336381266a1fSRichard Henderson 
trans_VMMLA_b16(DisasContext * s,arg_VMMLA_b16 * a)336481266a1fSRichard Henderson static bool trans_VMMLA_b16(DisasContext *s, arg_VMMLA_b16 *a)
336581266a1fSRichard Henderson {
336681266a1fSRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
336781266a1fSRichard Henderson         return false;
336881266a1fSRichard Henderson     }
33692da2d7dcSPeter Maydell     return do_neon_ddda_env(s, 7, a->vd, a->vn, a->vm, 0,
337081266a1fSRichard Henderson                             gen_helper_gvec_bfmmla);
337181266a1fSRichard Henderson }
33725693887fSRichard Henderson 
trans_VFMA_b16(DisasContext * s,arg_VFMA_b16 * a)33735693887fSRichard Henderson static bool trans_VFMA_b16(DisasContext *s, arg_VFMA_b16 *a)
33745693887fSRichard Henderson {
33755693887fSRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
33765693887fSRichard Henderson         return false;
33775693887fSRichard Henderson     }
33785693887fSRichard Henderson     return do_neon_ddda_fpst(s, 7, a->vd, a->vn, a->vm, a->q, FPST_STD,
33795693887fSRichard Henderson                              gen_helper_gvec_bfmlal);
33805693887fSRichard Henderson }
3381458d0ab6SRichard Henderson 
trans_VFMA_b16_scal(DisasContext * s,arg_VFMA_b16_scal * a)3382458d0ab6SRichard Henderson static bool trans_VFMA_b16_scal(DisasContext *s, arg_VFMA_b16_scal *a)
3383458d0ab6SRichard Henderson {
3384458d0ab6SRichard Henderson     if (!dc_isar_feature(aa32_bf16, s)) {
3385458d0ab6SRichard Henderson         return false;
3386458d0ab6SRichard Henderson     }
3387458d0ab6SRichard Henderson     return do_neon_ddda_fpst(s, 6, a->vd, a->vn, a->vm,
3388458d0ab6SRichard Henderson                              (a->index << 1) | a->q, FPST_STD,
3389458d0ab6SRichard Henderson                              gen_helper_gvec_bfmlal_idx);
3390458d0ab6SRichard Henderson }
3391