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