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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 14107b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 14117b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 14127b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 14137b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_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) 141724018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 141824018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 } 3053*f0632d48SRichard Henderson return do_2misc_vec(s, a, gen_gvec_fabs); 305484eae770SPeter Maydell } 305584eae770SPeter Maydell 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 } 3065*f0632d48SRichard Henderson return do_2misc_vec(s, a, gen_gvec_fneg); 306684eae770SPeter Maydell } 306784eae770SPeter Maydell 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 } 307384eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 307484eae770SPeter Maydell } 307584eae770SPeter Maydell 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 } 308184eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 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 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 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 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 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 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 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 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 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 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 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 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 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 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