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 151505fce50SRichard Henderson static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, 152505fce50SRichard Henderson int data, ARMFPStatusFlavour fp_flavour, 153505fce50SRichard Henderson gen_helper_gvec_4_ptr *fn_gvec_ptr) 154afff8de0SPeter Maydell { 155afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 156505fce50SRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 157afff8de0SPeter Maydell return false; 158afff8de0SPeter Maydell } 159afff8de0SPeter Maydell 160505fce50SRichard Henderson /* 161505fce50SRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 162505fce50SRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 163505fce50SRichard Henderson * when we have mixed Q- and D-reg inputs. 164505fce50SRichard Henderson */ 165505fce50SRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 166afff8de0SPeter Maydell return false; 167afff8de0SPeter Maydell } 168afff8de0SPeter Maydell 169afff8de0SPeter Maydell if (!vfp_access_check(s)) { 170afff8de0SPeter Maydell return true; 171afff8de0SPeter Maydell } 172afff8de0SPeter Maydell 173505fce50SRichard Henderson int opr_sz = q ? 16 : 8; 174505fce50SRichard Henderson TCGv_ptr fpst = fpstatus_ptr(fp_flavour); 175505fce50SRichard Henderson 176505fce50SRichard Henderson tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd), 177505fce50SRichard Henderson vfp_reg_offset(1, vn), 178505fce50SRichard Henderson vfp_reg_offset(1, vm), 179505fce50SRichard Henderson vfp_reg_offset(1, vd), 180505fce50SRichard Henderson fpst, opr_sz, opr_sz, data, fn_gvec_ptr); 181afff8de0SPeter Maydell return true; 182afff8de0SPeter Maydell } 18394d5eb7bSPeter Maydell 184505fce50SRichard Henderson static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 185505fce50SRichard Henderson { 186505fce50SRichard Henderson if (!dc_isar_feature(aa32_vcma, s)) { 187505fce50SRichard Henderson return false; 188505fce50SRichard Henderson } 189505fce50SRichard Henderson if (a->size == MO_16) { 190505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 191505fce50SRichard Henderson return false; 192505fce50SRichard Henderson } 193505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 194505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah); 195505fce50SRichard Henderson } 196505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 197505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas); 198505fce50SRichard Henderson } 199505fce50SRichard Henderson 20094d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 20194d5eb7bSPeter Maydell { 20294d5eb7bSPeter Maydell int opr_sz; 20394d5eb7bSPeter Maydell TCGv_ptr fpst; 20494d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 20594d5eb7bSPeter Maydell 20694d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 207d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 20894d5eb7bSPeter Maydell return false; 20994d5eb7bSPeter Maydell } 21094d5eb7bSPeter Maydell 21194d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 21294d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 21394d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 21494d5eb7bSPeter Maydell return false; 21594d5eb7bSPeter Maydell } 21694d5eb7bSPeter Maydell 21794d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 21894d5eb7bSPeter Maydell return false; 21994d5eb7bSPeter Maydell } 22094d5eb7bSPeter Maydell 22194d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 22294d5eb7bSPeter Maydell return true; 22394d5eb7bSPeter Maydell } 22494d5eb7bSPeter Maydell 22594d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 226d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 227d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 228d186a485SPeter Maydell gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds; 22994d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 23094d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 23194d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 23294d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 23394d5eb7bSPeter Maydell fn_gvec_ptr); 23494d5eb7bSPeter Maydell return true; 23594d5eb7bSPeter Maydell } 23632da0e33SPeter Maydell 237f0ad96cbSRichard Henderson static bool trans_VSDOT(DisasContext *s, arg_VSDOT *a) 23832da0e33SPeter Maydell { 23932da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 24032da0e33SPeter Maydell return false; 24132da0e33SPeter Maydell } 2425a46304cSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 243f0ad96cbSRichard Henderson gen_helper_gvec_sdot_b); 244f0ad96cbSRichard Henderson } 245f0ad96cbSRichard Henderson 246f0ad96cbSRichard Henderson static bool trans_VUDOT(DisasContext *s, arg_VUDOT *a) 247f0ad96cbSRichard Henderson { 248f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 249f0ad96cbSRichard Henderson return false; 250f0ad96cbSRichard Henderson } 251f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 252f0ad96cbSRichard Henderson gen_helper_gvec_udot_b); 25332da0e33SPeter Maydell } 2549a107e7bSPeter Maydell 25551879c67SRichard Henderson static bool trans_VUSDOT(DisasContext *s, arg_VUSDOT *a) 25651879c67SRichard Henderson { 25751879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 25851879c67SRichard Henderson return false; 25951879c67SRichard Henderson } 26051879c67SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 26151879c67SRichard Henderson gen_helper_gvec_usdot_b); 26251879c67SRichard Henderson } 26351879c67SRichard Henderson 264cb8657f7SRichard Henderson static bool trans_VDOT_b16(DisasContext *s, arg_VDOT_b16 *a) 265cb8657f7SRichard Henderson { 266cb8657f7SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 267cb8657f7SRichard Henderson return false; 268cb8657f7SRichard Henderson } 269cb8657f7SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 270cb8657f7SRichard Henderson gen_helper_gvec_bfdot); 271cb8657f7SRichard Henderson } 272cb8657f7SRichard Henderson 2739a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 2749a107e7bSPeter Maydell { 2759a107e7bSPeter Maydell int opr_sz; 2769a107e7bSPeter Maydell 2779a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 2789a107e7bSPeter Maydell return false; 2799a107e7bSPeter Maydell } 2809a107e7bSPeter Maydell 2819a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2829a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2839a107e7bSPeter Maydell (a->vd & 0x10)) { 2849a107e7bSPeter Maydell return false; 2859a107e7bSPeter Maydell } 2869a107e7bSPeter Maydell 2879a107e7bSPeter Maydell if (a->vd & a->q) { 2889a107e7bSPeter Maydell return false; 2899a107e7bSPeter Maydell } 2909a107e7bSPeter Maydell 2919a107e7bSPeter Maydell if (!vfp_access_check(s)) { 2929a107e7bSPeter Maydell return true; 2939a107e7bSPeter Maydell } 2949a107e7bSPeter Maydell 2959a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 2969a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 2979a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 2989a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 299ad75a51eSRichard Henderson tcg_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 3009a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 3019a107e7bSPeter Maydell return true; 3029a107e7bSPeter Maydell } 3037e1b5d61SPeter Maydell 3047e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 3057e1b5d61SPeter Maydell { 306505fce50SRichard Henderson int data = (a->index << 2) | a->rot; 3077e1b5d61SPeter Maydell 3087e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 3097e1b5d61SPeter Maydell return false; 3107e1b5d61SPeter Maydell } 311505fce50SRichard Henderson if (a->size == MO_16) { 312505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 3137e1b5d61SPeter Maydell return false; 3147e1b5d61SPeter Maydell } 315505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 316505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah_idx); 3177e1b5d61SPeter Maydell } 318505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 319505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas_idx); 3207e1b5d61SPeter Maydell } 32135f5d4d1SPeter Maydell 322f0ad96cbSRichard Henderson static bool trans_VSDOT_scalar(DisasContext *s, arg_VSDOT_scalar *a) 32335f5d4d1SPeter Maydell { 32435f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 32535f5d4d1SPeter Maydell return false; 32635f5d4d1SPeter Maydell } 3275a46304cSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 328f0ad96cbSRichard Henderson gen_helper_gvec_sdot_idx_b); 329f0ad96cbSRichard Henderson } 330f0ad96cbSRichard Henderson 331f0ad96cbSRichard Henderson static bool trans_VUDOT_scalar(DisasContext *s, arg_VUDOT_scalar *a) 332f0ad96cbSRichard Henderson { 333f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 334f0ad96cbSRichard Henderson return false; 335f0ad96cbSRichard Henderson } 336f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 337f0ad96cbSRichard Henderson gen_helper_gvec_udot_idx_b); 33835f5d4d1SPeter Maydell } 339d27e82f7SPeter Maydell 34051879c67SRichard Henderson static bool trans_VUSDOT_scalar(DisasContext *s, arg_VUSDOT_scalar *a) 34151879c67SRichard Henderson { 34251879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 34351879c67SRichard Henderson return false; 34451879c67SRichard Henderson } 34551879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 34651879c67SRichard Henderson gen_helper_gvec_usdot_idx_b); 34751879c67SRichard Henderson } 34851879c67SRichard Henderson 34951879c67SRichard Henderson static bool trans_VSUDOT_scalar(DisasContext *s, arg_VSUDOT_scalar *a) 35051879c67SRichard Henderson { 35151879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 35251879c67SRichard Henderson return false; 35351879c67SRichard Henderson } 35451879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 35551879c67SRichard Henderson gen_helper_gvec_sudot_idx_b); 35651879c67SRichard Henderson } 35751879c67SRichard Henderson 35883914478SRichard Henderson static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a) 35983914478SRichard Henderson { 36083914478SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 36183914478SRichard Henderson return false; 36283914478SRichard Henderson } 36383914478SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 36483914478SRichard Henderson gen_helper_gvec_bfdot_idx); 36583914478SRichard Henderson } 36683914478SRichard Henderson 367d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 368d27e82f7SPeter Maydell { 369d27e82f7SPeter Maydell int opr_sz; 370d27e82f7SPeter Maydell 371d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 372d27e82f7SPeter Maydell return false; 373d27e82f7SPeter Maydell } 374d27e82f7SPeter Maydell 375d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 376d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 377d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 378d27e82f7SPeter Maydell return false; 379d27e82f7SPeter Maydell } 380d27e82f7SPeter Maydell 381d27e82f7SPeter Maydell if (a->vd & a->q) { 382d27e82f7SPeter Maydell return false; 383d27e82f7SPeter Maydell } 384d27e82f7SPeter Maydell 385d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 386d27e82f7SPeter Maydell return true; 387d27e82f7SPeter Maydell } 388d27e82f7SPeter Maydell 389d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 390d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 391d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 392d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 393ad75a51eSRichard Henderson tcg_env, opr_sz, opr_sz, 394d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 395d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 396d27e82f7SPeter Maydell return true; 397d27e82f7SPeter Maydell } 398a27b4630SPeter Maydell 399a27b4630SPeter Maydell static struct { 400a27b4630SPeter Maydell int nregs; 401a27b4630SPeter Maydell int interleave; 402a27b4630SPeter Maydell int spacing; 403a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 404a27b4630SPeter Maydell {1, 4, 1}, 405a27b4630SPeter Maydell {1, 4, 2}, 406a27b4630SPeter Maydell {4, 1, 1}, 407a27b4630SPeter Maydell {2, 2, 2}, 408a27b4630SPeter Maydell {1, 3, 1}, 409a27b4630SPeter Maydell {1, 3, 2}, 410a27b4630SPeter Maydell {3, 1, 1}, 411a27b4630SPeter Maydell {1, 1, 1}, 412a27b4630SPeter Maydell {1, 2, 1}, 413a27b4630SPeter Maydell {1, 2, 2}, 414a27b4630SPeter Maydell {2, 1, 1} 415a27b4630SPeter Maydell }; 416a27b4630SPeter Maydell 417a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 418a27b4630SPeter Maydell int stride) 419a27b4630SPeter Maydell { 420a27b4630SPeter Maydell if (rm != 15) { 421a27b4630SPeter Maydell TCGv_i32 base; 422a27b4630SPeter Maydell 423a27b4630SPeter Maydell base = load_reg(s, rn); 424a27b4630SPeter Maydell if (rm == 13) { 425a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 426a27b4630SPeter Maydell } else { 427a27b4630SPeter Maydell TCGv_i32 index; 428a27b4630SPeter Maydell index = load_reg(s, rm); 429a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 430a27b4630SPeter Maydell } 431a27b4630SPeter Maydell store_reg(s, rn, base); 432a27b4630SPeter Maydell } 433a27b4630SPeter Maydell } 434a27b4630SPeter Maydell 435a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 436a27b4630SPeter Maydell { 437a27b4630SPeter Maydell /* Neon load/store multiple structures */ 438a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 4397c68c196SRichard Henderson MemOp mop, align, endian; 440a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 441a27b4630SPeter Maydell int size = a->size; 442a27b4630SPeter Maydell TCGv_i64 tmp64; 443d9b47e97SRichard Henderson TCGv_i32 addr; 444a27b4630SPeter Maydell 445a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 446a27b4630SPeter Maydell return false; 447a27b4630SPeter Maydell } 448a27b4630SPeter Maydell 449a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 450a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 451a27b4630SPeter Maydell return false; 452a27b4630SPeter Maydell } 453a27b4630SPeter Maydell if (a->itype > 10) { 454a27b4630SPeter Maydell return false; 455a27b4630SPeter Maydell } 456a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 457a27b4630SPeter Maydell switch (a->itype & 0xc) { 458a27b4630SPeter Maydell case 4: 459a27b4630SPeter Maydell if (a->align >= 2) { 460a27b4630SPeter Maydell return false; 461a27b4630SPeter Maydell } 462a27b4630SPeter Maydell break; 463a27b4630SPeter Maydell case 8: 464a27b4630SPeter Maydell if (a->align == 3) { 465a27b4630SPeter Maydell return false; 466a27b4630SPeter Maydell } 467a27b4630SPeter Maydell break; 468a27b4630SPeter Maydell default: 469a27b4630SPeter Maydell break; 470a27b4630SPeter Maydell } 471a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 472a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 473a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 474a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 475a27b4630SPeter Maydell return false; 476a27b4630SPeter Maydell } 477a27b4630SPeter Maydell 478a27b4630SPeter Maydell if (!vfp_access_check(s)) { 479a27b4630SPeter Maydell return true; 480a27b4630SPeter Maydell } 481a27b4630SPeter Maydell 482a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 4837c68c196SRichard Henderson endian = s->be_data; 484a27b4630SPeter Maydell if (size == 0) { 485a27b4630SPeter Maydell endian = MO_LE; 486a27b4630SPeter Maydell } 4877c68c196SRichard Henderson 4887c68c196SRichard Henderson /* Enforce alignment requested by the instruction */ 4897c68c196SRichard Henderson if (a->align) { 4907c68c196SRichard Henderson align = pow2_align(a->align + 2); /* 4 ** a->align */ 4917c68c196SRichard Henderson } else { 4927c68c196SRichard Henderson align = s->align_mem ? MO_ALIGN : 0; 4937c68c196SRichard Henderson } 4947c68c196SRichard Henderson 495a27b4630SPeter Maydell /* 496a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 497a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 498a27b4630SPeter Maydell */ 499a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 5007c68c196SRichard Henderson /* Retain any natural alignment. */ 5017c68c196SRichard Henderson if (align == MO_ALIGN) { 5027c68c196SRichard Henderson align = pow2_align(size); 5037c68c196SRichard Henderson } 504a27b4630SPeter Maydell size = 3; 505a27b4630SPeter Maydell } 5067c68c196SRichard Henderson 507a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 508a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 509a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 5107c68c196SRichard Henderson 5117c68c196SRichard Henderson mop = endian | size | align; 512a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 513a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 514a27b4630SPeter Maydell int xs; 515a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 516a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 517a27b4630SPeter Maydell 518a27b4630SPeter Maydell if (a->l) { 5197c68c196SRichard Henderson gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop); 520a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 521a27b4630SPeter Maydell } else { 522a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 5237c68c196SRichard Henderson gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); 524a27b4630SPeter Maydell } 525d9b47e97SRichard Henderson tcg_gen_addi_i32(addr, addr, 1 << size); 5267c68c196SRichard Henderson 5277c68c196SRichard Henderson /* Subsequent memory operations inherit alignment */ 5287c68c196SRichard Henderson mop &= ~MO_AMASK; 529a27b4630SPeter Maydell } 530a27b4630SPeter Maydell } 531a27b4630SPeter Maydell } 532a27b4630SPeter Maydell 533a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 534a27b4630SPeter Maydell return true; 535a27b4630SPeter Maydell } 5363698747cSPeter Maydell 5373698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5383698747cSPeter Maydell { 5393698747cSPeter Maydell /* Neon load single structure to all lanes */ 5403698747cSPeter Maydell int reg, stride, vec_size; 5413698747cSPeter Maydell int vd = a->vd; 5423698747cSPeter Maydell int size = a->size; 5433698747cSPeter Maydell int nregs = a->n + 1; 5443698747cSPeter Maydell TCGv_i32 addr, tmp; 545a8502b37SRichard Henderson MemOp mop, align; 5463698747cSPeter Maydell 5473698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5483698747cSPeter Maydell return false; 5493698747cSPeter Maydell } 5503698747cSPeter Maydell 5513698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5523698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5533698747cSPeter Maydell return false; 5543698747cSPeter Maydell } 5553698747cSPeter Maydell 556a8502b37SRichard Henderson align = 0; 5573698747cSPeter Maydell if (size == 3) { 5583698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5593698747cSPeter Maydell return false; 5603698747cSPeter Maydell } 5613698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 562a8502b37SRichard Henderson size = MO_32; 563a8502b37SRichard Henderson align = MO_ALIGN_16; 564a8502b37SRichard Henderson } else if (a->a) { 565a8502b37SRichard Henderson switch (nregs) { 566a8502b37SRichard Henderson case 1: 567a8502b37SRichard Henderson if (size == 0) { 5683698747cSPeter Maydell return false; 5693698747cSPeter Maydell } 570a8502b37SRichard Henderson align = MO_ALIGN; 571a8502b37SRichard Henderson break; 572a8502b37SRichard Henderson case 2: 573a8502b37SRichard Henderson align = pow2_align(size + 1); 574a8502b37SRichard Henderson break; 575a8502b37SRichard Henderson case 3: 5763698747cSPeter Maydell return false; 577a8502b37SRichard Henderson case 4: 5783a661024SClément Chigot if (size == 2) { 5793a661024SClément Chigot align = pow2_align(3); 5803a661024SClément Chigot } else { 581a8502b37SRichard Henderson align = pow2_align(size + 2); 5823a661024SClément Chigot } 583a8502b37SRichard Henderson break; 584a8502b37SRichard Henderson default: 585a8502b37SRichard Henderson g_assert_not_reached(); 586a8502b37SRichard Henderson } 5873698747cSPeter Maydell } 5883698747cSPeter Maydell 5893698747cSPeter Maydell if (!vfp_access_check(s)) { 5903698747cSPeter Maydell return true; 5913698747cSPeter Maydell } 5923698747cSPeter Maydell 5933698747cSPeter Maydell /* 5943698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 5953698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 5963698747cSPeter Maydell */ 5973698747cSPeter Maydell stride = a->t ? 2 : 1; 5983698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 599a8502b37SRichard Henderson mop = size | align; 6003698747cSPeter Maydell tmp = tcg_temp_new_i32(); 6013698747cSPeter Maydell addr = tcg_temp_new_i32(); 6023698747cSPeter Maydell load_reg_var(s, addr, a->rn); 6033698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 604a8502b37SRichard Henderson gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); 6053698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 6063698747cSPeter Maydell /* 6073698747cSPeter Maydell * We cannot write 16 bytes at once because the 6083698747cSPeter Maydell * destination is unaligned. 6093698747cSPeter Maydell */ 610015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6113698747cSPeter Maydell 8, 8, tmp); 612015ee81aSRichard Henderson tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1), 613015ee81aSRichard Henderson neon_full_reg_offset(vd), 8, 8); 6143698747cSPeter Maydell } else { 615015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6163698747cSPeter Maydell vec_size, vec_size, tmp); 6173698747cSPeter Maydell } 6183698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 6193698747cSPeter Maydell vd += stride; 620a8502b37SRichard Henderson 621a8502b37SRichard Henderson /* Subsequent memory operations inherit alignment */ 622a8502b37SRichard Henderson mop &= ~MO_AMASK; 6233698747cSPeter Maydell } 6243698747cSPeter Maydell 6253698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 6263698747cSPeter Maydell 6273698747cSPeter Maydell return true; 6283698747cSPeter Maydell } 629123ce4e3SPeter Maydell 630123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 631123ce4e3SPeter Maydell { 632123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 633123ce4e3SPeter Maydell int reg; 634123ce4e3SPeter Maydell int nregs = a->n + 1; 635123ce4e3SPeter Maydell int vd = a->vd; 636123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 63788976ff0SRichard Henderson MemOp mop; 638123ce4e3SPeter Maydell 639123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 640123ce4e3SPeter Maydell return false; 641123ce4e3SPeter Maydell } 642123ce4e3SPeter Maydell 643123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 644123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 645123ce4e3SPeter Maydell return false; 646123ce4e3SPeter Maydell } 647123ce4e3SPeter Maydell 648123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 649123ce4e3SPeter Maydell switch (nregs) { 650123ce4e3SPeter Maydell case 1: 651c64ee036SPeter Maydell if (a->stride != 1) { 652c64ee036SPeter Maydell return false; 653c64ee036SPeter Maydell } 654123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 655a736cbc3SRichard Henderson (a->size == 2 && (a->align == 1 || a->align == 2))) { 656123ce4e3SPeter Maydell return false; 657123ce4e3SPeter Maydell } 658123ce4e3SPeter Maydell break; 659123ce4e3SPeter Maydell case 2: 660123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 661123ce4e3SPeter Maydell return false; 662123ce4e3SPeter Maydell } 663123ce4e3SPeter Maydell break; 66441c5a0f7SPeter Maydell case 3: 66541c5a0f7SPeter Maydell if (a->align != 0) { 66641c5a0f7SPeter Maydell return false; 66741c5a0f7SPeter Maydell } 66841c5a0f7SPeter Maydell break; 669123ce4e3SPeter Maydell case 4: 670a736cbc3SRichard Henderson if (a->size == 2 && a->align == 3) { 671123ce4e3SPeter Maydell return false; 672123ce4e3SPeter Maydell } 673123ce4e3SPeter Maydell break; 674123ce4e3SPeter Maydell default: 675d385a605SRichard Henderson g_assert_not_reached(); 676123ce4e3SPeter Maydell } 677123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 678123ce4e3SPeter Maydell /* 679123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 680123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 681123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 682123ce4e3SPeter Maydell */ 683123ce4e3SPeter Maydell return false; 684123ce4e3SPeter Maydell } 685123ce4e3SPeter Maydell 686123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 687123ce4e3SPeter Maydell return true; 688123ce4e3SPeter Maydell } 689123ce4e3SPeter Maydell 69088976ff0SRichard Henderson /* Pick up SCTLR settings */ 69188976ff0SRichard Henderson mop = finalize_memop(s, a->size); 69288976ff0SRichard Henderson 69388976ff0SRichard Henderson if (a->align) { 69488976ff0SRichard Henderson MemOp align_op; 69588976ff0SRichard Henderson 69688976ff0SRichard Henderson switch (nregs) { 69788976ff0SRichard Henderson case 1: 69888976ff0SRichard Henderson /* For VLD1, use natural alignment. */ 69988976ff0SRichard Henderson align_op = MO_ALIGN; 70088976ff0SRichard Henderson break; 70188976ff0SRichard Henderson case 2: 70288976ff0SRichard Henderson /* For VLD2, use double alignment. */ 70388976ff0SRichard Henderson align_op = pow2_align(a->size + 1); 70488976ff0SRichard Henderson break; 70588976ff0SRichard Henderson case 4: 70688976ff0SRichard Henderson if (a->size == MO_32) { 70788976ff0SRichard Henderson /* 70888976ff0SRichard Henderson * For VLD4.32, align = 1 is double alignment, align = 2 is 70988976ff0SRichard Henderson * quad alignment; align = 3 is rejected above. 71088976ff0SRichard Henderson */ 71188976ff0SRichard Henderson align_op = pow2_align(a->size + a->align); 71288976ff0SRichard Henderson } else { 71388976ff0SRichard Henderson /* For VLD4.8 and VLD.16, we want quad alignment. */ 71488976ff0SRichard Henderson align_op = pow2_align(a->size + 2); 71588976ff0SRichard Henderson } 71688976ff0SRichard Henderson break; 71788976ff0SRichard Henderson default: 71888976ff0SRichard Henderson /* For VLD3, the alignment field is zero and rejected above. */ 71988976ff0SRichard Henderson g_assert_not_reached(); 72088976ff0SRichard Henderson } 72188976ff0SRichard Henderson 72288976ff0SRichard Henderson mop = (mop & ~MO_AMASK) | align_op; 72388976ff0SRichard Henderson } 72488976ff0SRichard Henderson 725123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 726123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 727123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 72888976ff0SRichard Henderson 729123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 730123ce4e3SPeter Maydell if (a->l) { 73188976ff0SRichard Henderson gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop); 732123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 733123ce4e3SPeter Maydell } else { /* Store */ 734123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 73588976ff0SRichard Henderson gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop); 736123ce4e3SPeter Maydell } 737123ce4e3SPeter Maydell vd += a->stride; 738123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 73988976ff0SRichard Henderson 74088976ff0SRichard Henderson /* Subsequent memory operations inherit alignment */ 74188976ff0SRichard Henderson mop &= ~MO_AMASK; 742123ce4e3SPeter Maydell } 743123ce4e3SPeter Maydell 744123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 745123ce4e3SPeter Maydell 746123ce4e3SPeter Maydell return true; 747123ce4e3SPeter Maydell } 748a4e143acSPeter Maydell 749a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 750a4e143acSPeter Maydell { 751a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 752015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 753015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 754015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 755a4e143acSPeter Maydell 756a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 757a4e143acSPeter Maydell return false; 758a4e143acSPeter Maydell } 759a4e143acSPeter Maydell 760a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 761a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 762a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 763a4e143acSPeter Maydell return false; 764a4e143acSPeter Maydell } 765a4e143acSPeter Maydell 766a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 767a4e143acSPeter Maydell return false; 768a4e143acSPeter Maydell } 769a4e143acSPeter Maydell 770a4e143acSPeter Maydell if (!vfp_access_check(s)) { 771a4e143acSPeter Maydell return true; 772a4e143acSPeter Maydell } 773a4e143acSPeter Maydell 774a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 775a4e143acSPeter Maydell return true; 776a4e143acSPeter Maydell } 777a4e143acSPeter Maydell 778a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 779a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 780a4e143acSPeter Maydell { \ 781a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 782a4e143acSPeter Maydell } 783a4e143acSPeter Maydell 784a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 785a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 78635a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 78735a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 78835a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 78935a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 79035a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 7918161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 7928161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 793c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 794c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 795c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 796c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 79735a548edSPeter Maydell 79835a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 79935a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 80035a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 80135a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 80235a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 80335a548edSPeter Maydell { \ 80435a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 80535a548edSPeter Maydell } \ 80635a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 80735a548edSPeter Maydell 80835a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 80935a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 81035a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 81136b59310SPeter Maydell 81236b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 81336b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 81436b59310SPeter Maydell { \ 81536b59310SPeter Maydell if (a->size == 3) { \ 81636b59310SPeter Maydell return false; \ 81736b59310SPeter Maydell } \ 81836b59310SPeter Maydell return do_3same(s, a, FUNC); \ 81936b59310SPeter Maydell } 82036b59310SPeter Maydell 82136b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 82236b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 82336b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 82436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 8250de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 82627106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 82727106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 8288161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 8297715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 8307715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 8317715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 8327715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 83302bd0cdbSPeter Maydell 83402bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 83502bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 83602bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 83702bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 83802bd0cdbSPeter Maydell { \ 83902bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 84002bd0cdbSPeter Maydell } \ 84102bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 84202bd0cdbSPeter Maydell 84302bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 84402bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 84502bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 84602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 84702bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 84802bd0cdbSPeter Maydell 849effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 850effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 851effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 852effa992fSRichard Henderson { \ 853effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 8540de34fd4SPeter Maydell } 8550de34fd4SPeter Maydell 856effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 857effa992fSRichard Henderson 8580de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 8590de34fd4SPeter Maydell { 8600de34fd4SPeter Maydell if (a->size != 0) { 8610de34fd4SPeter Maydell return false; 8620de34fd4SPeter Maydell } 8630de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 8640de34fd4SPeter Maydell } 865a0635695SPeter Maydell 866a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 867a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 868a0635695SPeter Maydell { \ 869a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 870a0635695SPeter Maydell return false; \ 871a0635695SPeter Maydell } \ 872a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 873a0635695SPeter Maydell return false; \ 874a0635695SPeter Maydell } \ 875a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 876a0635695SPeter Maydell } 877a0635695SPeter Maydell 878a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 879a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 88021290edfSPeter Maydell 881afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 882afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 883afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 884afc8b7d3SRichard Henderson { \ 885afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 886afc8b7d3SRichard Henderson return false; \ 887afc8b7d3SRichard Henderson } \ 888afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 88921290edfSPeter Maydell } 89021290edfSPeter Maydell 891afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 892afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 893afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 894afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 89521290edfSPeter Maydell 896effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 897effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 898effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 899effa992fSRichard Henderson { \ 900effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 901effa992fSRichard Henderson return false; \ 902effa992fSRichard Henderson } \ 903effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 90421290edfSPeter Maydell } 90521290edfSPeter Maydell 906effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 907effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 908effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 90935d4352fSPeter Maydell 91035d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 91135d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 91235d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 91335d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 91435d4352fSPeter Maydell { \ 91535d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 91635d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 91735d4352fSPeter Maydell } \ 91835d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 91935d4352fSPeter Maydell 92035d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 92135d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 92235d4352fSPeter Maydell { \ 923ad75a51eSRichard Henderson FUNC(d, tcg_env, n, m); \ 92435d4352fSPeter Maydell } \ 92535d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 92635d4352fSPeter Maydell 92735d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 92835d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 92935d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 93035d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 93135d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 93235d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 933cb294bcaSPeter Maydell 934cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 935cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 936cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 937cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 938cb294bcaSPeter Maydell { \ 939cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 940cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 941cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 942cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 943cb294bcaSPeter Maydell { 0 }, \ 944cb294bcaSPeter Maydell }; \ 945cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 946cb294bcaSPeter Maydell } \ 947cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 948cb294bcaSPeter Maydell { \ 949cb294bcaSPeter Maydell if (a->size > 2) { \ 950cb294bcaSPeter Maydell return false; \ 951cb294bcaSPeter Maydell } \ 952cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 953cb294bcaSPeter Maydell } 954cb294bcaSPeter Maydell 9556812dfdcSPeter Maydell /* 956ad75a51eSRichard Henderson * Some helper functions need to be passed the tcg_env. In order 9576812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 9586812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 9596812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 9606812dfdcSPeter Maydell */ 9616812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 9626812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 9636812dfdcSPeter Maydell { \ 964ad75a51eSRichard Henderson FUNC(d, tcg_env, n, m); \ 9656812dfdcSPeter Maydell } 9666812dfdcSPeter Maydell 9676812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 9686812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 9696812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 9706812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 9716812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9726812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9736812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9746812dfdcSPeter Maydell { \ 9756812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 9766812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9776812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9786812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9796812dfdcSPeter Maydell { 0 }, \ 9806812dfdcSPeter Maydell }; \ 9816812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 9826812dfdcSPeter Maydell } \ 9836812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9846812dfdcSPeter Maydell { \ 9856812dfdcSPeter Maydell if (a->size > 2) { \ 9866812dfdcSPeter Maydell return false; \ 9876812dfdcSPeter Maydell } \ 9886812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 9896812dfdcSPeter Maydell } 9906812dfdcSPeter Maydell 991cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 992cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 9938e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 9948e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 9958e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 9968e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 9976812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 9986812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 9996812dfdcSPeter Maydell 10006812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 10016812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 10026812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 10036812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 1004059c2398SPeter Maydell 1005059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 1006059c2398SPeter Maydell { 1007059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 1008059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1009059c2398SPeter Maydell 1010059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1011059c2398SPeter Maydell return false; 1012059c2398SPeter Maydell } 1013059c2398SPeter Maydell 1014059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1015059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1016059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1017059c2398SPeter Maydell return false; 1018059c2398SPeter Maydell } 1019059c2398SPeter Maydell 1020059c2398SPeter Maydell if (a->size == 3) { 1021059c2398SPeter Maydell return false; 1022059c2398SPeter Maydell } 1023059c2398SPeter Maydell 1024059c2398SPeter Maydell if (!vfp_access_check(s)) { 1025059c2398SPeter Maydell return true; 1026059c2398SPeter Maydell } 1027059c2398SPeter Maydell 1028059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1029059c2398SPeter Maydell 1030059c2398SPeter Maydell /* 1031059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 1032059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1033059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1034059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 1035059c2398SPeter Maydell */ 1036a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 1037a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 1038a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 1039a712266fSRichard Henderson 1040a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1041a712266fSRichard Henderson read_neon_element32(tmp2, a->vn, 1, MO_32); 1042059c2398SPeter Maydell fn(tmp, tmp, tmp2); 1043059c2398SPeter Maydell 1044a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 0, MO_32); 1045a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 1046059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 1047059c2398SPeter Maydell 1048a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 0, MO_32); 1049a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 1050a712266fSRichard Henderson 1051059c2398SPeter Maydell return true; 1052059c2398SPeter Maydell } 1053059c2398SPeter Maydell 1054059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 1055059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 1056059c2398SPeter Maydell { \ 1057059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 1058059c2398SPeter Maydell gen_helper_neon_##func##8, \ 1059059c2398SPeter Maydell gen_helper_neon_##func##16, \ 1060059c2398SPeter Maydell gen_helper_neon_##func##32, \ 1061059c2398SPeter Maydell }; \ 1062059c2398SPeter Maydell if (a->size > 2) { \ 1063059c2398SPeter Maydell return false; \ 1064059c2398SPeter Maydell } \ 1065059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 1066059c2398SPeter Maydell } 1067059c2398SPeter Maydell 1068059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 1069059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 1070059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 1071059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 1072059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 1073fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1074059c2398SPeter Maydell 1075059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1076059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1077059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1078059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1079fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 10807ecc28bcSPeter Maydell 10817ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 10827ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 10837ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 10847ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 10857ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 10867ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 10877ecc28bcSPeter Maydell { \ 10887ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 10897ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 10907ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 10917ecc28bcSPeter Maydell }; \ 10927ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 10937ecc28bcSPeter Maydell } \ 10947ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 10957ecc28bcSPeter Maydell { \ 10967ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 10977ecc28bcSPeter Maydell return false; \ 10987ecc28bcSPeter Maydell } \ 10997ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 11007ecc28bcSPeter Maydell } 11017ecc28bcSPeter Maydell 11027ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 11037ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1104a26a352bSPeter Maydell 1105e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1106e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1107a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1108a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1109a26a352bSPeter Maydell { \ 1110e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1111a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1112a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1113e4a6d4a6SPeter Maydell } 1114e4a6d4a6SPeter Maydell 1115e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1116e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1117e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1118a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1119a26a352bSPeter Maydell { \ 11206cf0f240SPeter Maydell if (a->size == MO_16) { \ 1121e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1122a26a352bSPeter Maydell return false; \ 1123a26a352bSPeter Maydell } \ 1124e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1125e4a6d4a6SPeter Maydell } \ 1126e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1127a26a352bSPeter Maydell } 1128a26a352bSPeter Maydell 1129a26a352bSPeter Maydell 1130e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1131e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1132e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1133e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 1134ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h) 1135ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h) 1136ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h) 1137bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h) 1138bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h) 1139e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h) 1140e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h) 1141e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h) 1142e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h) 1143cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h) 1144cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h) 1145ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h) 114640fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h) 1147*c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPADD, gen_helper_gvec_faddp_s, gen_helper_gvec_faddp_h) 1148*c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPMAX, gen_helper_gvec_fmaxp_s, gen_helper_gvec_fmaxp_h) 1149*c43a23e1SRichard Henderson DO_3S_FP_GVEC(VPMIN, gen_helper_gvec_fminp_s, gen_helper_gvec_fminp_h) 1150ab978335SPeter Maydell 1151e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s) 1152e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h) 1153e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s) 1154e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h) 1155e22705bbSPeter Maydell 1156d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1157d5fdf9e9SPeter Maydell { 1158d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1159d5fdf9e9SPeter Maydell return false; 1160d5fdf9e9SPeter Maydell } 1161d5fdf9e9SPeter Maydell 11626cf0f240SPeter Maydell if (a->size == MO_16) { 1163e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1164d5fdf9e9SPeter Maydell return false; 1165d5fdf9e9SPeter Maydell } 1166e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp16_3s); 1167e22705bbSPeter Maydell } 1168e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp32_3s); 1169d5fdf9e9SPeter Maydell } 1170d5fdf9e9SPeter Maydell 1171d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1172d5fdf9e9SPeter Maydell { 1173d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1174d5fdf9e9SPeter Maydell return false; 1175d5fdf9e9SPeter Maydell } 1176d5fdf9e9SPeter Maydell 11776cf0f240SPeter Maydell if (a->size == MO_16) { 1178e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1179d5fdf9e9SPeter Maydell return false; 1180d5fdf9e9SPeter Maydell } 1181e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp16_3s); 1182e22705bbSPeter Maydell } 1183e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp32_3s); 1184d5fdf9e9SPeter Maydell } 1185d5fdf9e9SPeter Maydell 1186d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1187d3c8c736SPeter Maydell { 1188d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1189d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1190015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1191015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 1192d3c8c736SPeter Maydell 1193d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1194d3c8c736SPeter Maydell return false; 1195d3c8c736SPeter Maydell } 1196d3c8c736SPeter Maydell 1197d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1198d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1199d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1200d3c8c736SPeter Maydell return false; 1201d3c8c736SPeter Maydell } 1202d3c8c736SPeter Maydell 1203d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1204d3c8c736SPeter Maydell return false; 1205d3c8c736SPeter Maydell } 1206d3c8c736SPeter Maydell 1207d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1208d3c8c736SPeter Maydell return true; 1209d3c8c736SPeter Maydell } 1210d3c8c736SPeter Maydell 1211d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1212d3c8c736SPeter Maydell return true; 1213d3c8c736SPeter Maydell } 1214d3c8c736SPeter Maydell 1215d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1216d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1217d3c8c736SPeter Maydell { \ 1218d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1219d3c8c736SPeter Maydell } \ 1220d3c8c736SPeter Maydell 1221d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1222d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1223434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1224434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1225434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1226434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1227434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1228434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1229434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 123066432d6bSPeter Maydell 123166432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 123266432d6bSPeter Maydell { 123366432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 123466432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 123566432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 123666432d6bSPeter Maydell } 123766432d6bSPeter Maydell 123866432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 123966432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 124066432d6bSPeter Maydell { 124166432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 124266432d6bSPeter Maydell } 124366432d6bSPeter Maydell 124466432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 124566432d6bSPeter Maydell { 124666432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 124766432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 124866432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 124966432d6bSPeter Maydell } else { 125066432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 125166432d6bSPeter Maydell } 125266432d6bSPeter Maydell } 125337bfce81SPeter Maydell 125437bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 125537bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 125637bfce81SPeter Maydell { 125737bfce81SPeter Maydell /* 125837bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 1259ad75a51eSRichard Henderson * function needs to be passed tcg_env. 126037bfce81SPeter Maydell */ 126137bfce81SPeter Maydell TCGv_i64 constimm; 126237bfce81SPeter Maydell int pass; 126337bfce81SPeter Maydell 126437bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 126537bfce81SPeter Maydell return false; 126637bfce81SPeter Maydell } 126737bfce81SPeter Maydell 126837bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 126937bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 127037bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 127137bfce81SPeter Maydell return false; 127237bfce81SPeter Maydell } 127337bfce81SPeter Maydell 127437bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 127537bfce81SPeter Maydell return false; 127637bfce81SPeter Maydell } 127737bfce81SPeter Maydell 127837bfce81SPeter Maydell if (!vfp_access_check(s)) { 127937bfce81SPeter Maydell return true; 128037bfce81SPeter Maydell } 128137bfce81SPeter Maydell 128237bfce81SPeter Maydell /* 128337bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 128437bfce81SPeter Maydell * by immediate using the variable shift operations. 128537bfce81SPeter Maydell */ 1286d9b47e97SRichard Henderson constimm = tcg_constant_i64(dup_const(a->size, a->shift)); 128737bfce81SPeter Maydell 128837bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 128937bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 129037bfce81SPeter Maydell 12910aa8e700SRichard Henderson read_neon_element64(tmp, a->vm, pass, MO_64); 1292ad75a51eSRichard Henderson fn(tmp, tcg_env, tmp, constimm); 12930aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, pass, MO_64); 129437bfce81SPeter Maydell } 129537bfce81SPeter Maydell return true; 129637bfce81SPeter Maydell } 129737bfce81SPeter Maydell 129837bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 129937bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 130037bfce81SPeter Maydell { 130137bfce81SPeter Maydell /* 130237bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 1303ad75a51eSRichard Henderson * helper needs to be passed tcg_env. 130437bfce81SPeter Maydell */ 1305a712266fSRichard Henderson TCGv_i32 constimm, tmp; 130637bfce81SPeter Maydell int pass; 130737bfce81SPeter Maydell 130837bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 130937bfce81SPeter Maydell return false; 131037bfce81SPeter Maydell } 131137bfce81SPeter Maydell 131237bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 131337bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 131437bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 131537bfce81SPeter Maydell return false; 131637bfce81SPeter Maydell } 131737bfce81SPeter Maydell 131837bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 131937bfce81SPeter Maydell return false; 132037bfce81SPeter Maydell } 132137bfce81SPeter Maydell 132237bfce81SPeter Maydell if (!vfp_access_check(s)) { 132337bfce81SPeter Maydell return true; 132437bfce81SPeter Maydell } 132537bfce81SPeter Maydell 132637bfce81SPeter Maydell /* 132737bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 132837bfce81SPeter Maydell * by immediate using the variable shift operations. 132937bfce81SPeter Maydell */ 1330d9b47e97SRichard Henderson constimm = tcg_constant_i32(dup_const(a->size, a->shift)); 1331a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 133237bfce81SPeter Maydell 133337bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 1334a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 1335ad75a51eSRichard Henderson fn(tmp, tcg_env, tmp, constimm); 1336a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 133737bfce81SPeter Maydell } 133837bfce81SPeter Maydell return true; 133937bfce81SPeter Maydell } 134037bfce81SPeter Maydell 134137bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 134237bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 134337bfce81SPeter Maydell { \ 134437bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 134537bfce81SPeter Maydell } \ 134637bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 134737bfce81SPeter Maydell { \ 134837bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 134937bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 135037bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 135137bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 135237bfce81SPeter Maydell }; \ 135337bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 135437bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 135537bfce81SPeter Maydell } 135637bfce81SPeter Maydell 135737bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 135837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 135937bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1360712182d3SPeter Maydell 1361712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1362712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1363712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1364712182d3SPeter Maydell { 1365712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1366712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1367712182d3SPeter Maydell TCGv_i32 rd; 1368712182d3SPeter Maydell 1369712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1370712182d3SPeter Maydell return false; 1371712182d3SPeter Maydell } 1372712182d3SPeter Maydell 1373712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1374712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1375712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1376712182d3SPeter Maydell return false; 1377712182d3SPeter Maydell } 1378712182d3SPeter Maydell 1379712182d3SPeter Maydell if (a->vm & 1) { 1380712182d3SPeter Maydell return false; 1381712182d3SPeter Maydell } 1382712182d3SPeter Maydell 1383712182d3SPeter Maydell if (!vfp_access_check(s)) { 1384712182d3SPeter Maydell return true; 1385712182d3SPeter Maydell } 1386712182d3SPeter Maydell 1387712182d3SPeter Maydell /* 1388712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1389712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1390712182d3SPeter Maydell */ 1391d9b47e97SRichard Henderson constimm = tcg_constant_i64(-a->shift); 1392712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1393712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1394a712266fSRichard Henderson rd = tcg_temp_new_i32(); 1395712182d3SPeter Maydell 1396712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 13970aa8e700SRichard Henderson read_neon_element64(rm1, a->vm, 0, MO_64); 13980aa8e700SRichard Henderson read_neon_element64(rm2, a->vm, 1, MO_64); 1399712182d3SPeter Maydell 1400712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1401ad75a51eSRichard Henderson narrowfn(rd, tcg_env, rm1); 1402a712266fSRichard Henderson write_neon_element32(rd, a->vd, 0, MO_32); 1403712182d3SPeter Maydell 1404712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1405ad75a51eSRichard Henderson narrowfn(rd, tcg_env, rm2); 1406a712266fSRichard Henderson write_neon_element32(rd, a->vd, 1, MO_32); 1407712182d3SPeter Maydell 1408712182d3SPeter Maydell return true; 1409712182d3SPeter Maydell } 1410712182d3SPeter Maydell 1411712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1412712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1413712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1414712182d3SPeter Maydell { 1415712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1416712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1417712182d3SPeter Maydell TCGv_i64 rtmp; 1418712182d3SPeter Maydell uint32_t imm; 1419712182d3SPeter Maydell 1420712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1421712182d3SPeter Maydell return false; 1422712182d3SPeter Maydell } 1423712182d3SPeter Maydell 1424712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1425712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1426712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1427712182d3SPeter Maydell return false; 1428712182d3SPeter Maydell } 1429712182d3SPeter Maydell 1430712182d3SPeter Maydell if (a->vm & 1) { 1431712182d3SPeter Maydell return false; 1432712182d3SPeter Maydell } 1433712182d3SPeter Maydell 1434712182d3SPeter Maydell if (!vfp_access_check(s)) { 1435712182d3SPeter Maydell return true; 1436712182d3SPeter Maydell } 1437712182d3SPeter Maydell 1438712182d3SPeter Maydell /* 1439712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1440712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1441712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1442712182d3SPeter Maydell */ 1443712182d3SPeter Maydell if (a->size == 1) { 1444712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1445712182d3SPeter Maydell imm |= imm << 16; 1446712182d3SPeter Maydell } else { 1447712182d3SPeter Maydell /* size == 2 */ 1448712182d3SPeter Maydell imm = -a->shift; 1449712182d3SPeter Maydell } 1450d9b47e97SRichard Henderson constimm = tcg_constant_i32(imm); 1451712182d3SPeter Maydell 1452712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1453a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1454a712266fSRichard Henderson rm2 = tcg_temp_new_i32(); 1455a712266fSRichard Henderson rm3 = tcg_temp_new_i32(); 1456a712266fSRichard Henderson rm4 = tcg_temp_new_i32(); 1457a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 0, MO_32); 1458a712266fSRichard Henderson read_neon_element32(rm2, a->vm, 1, MO_32); 1459a712266fSRichard Henderson read_neon_element32(rm3, a->vm, 2, MO_32); 1460a712266fSRichard Henderson read_neon_element32(rm4, a->vm, 3, MO_32); 1461712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1462712182d3SPeter Maydell 1463712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1464712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1465712182d3SPeter Maydell 1466712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1467712182d3SPeter Maydell 1468ad75a51eSRichard Henderson narrowfn(rm1, tcg_env, rtmp); 1469a712266fSRichard Henderson write_neon_element32(rm1, a->vd, 0, MO_32); 1470712182d3SPeter Maydell 1471712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1472712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1473712182d3SPeter Maydell 1474712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1475712182d3SPeter Maydell 1476ad75a51eSRichard Henderson narrowfn(rm3, tcg_env, rtmp); 1477a712266fSRichard Henderson write_neon_element32(rm3, a->vd, 1, MO_32); 1478712182d3SPeter Maydell return true; 1479712182d3SPeter Maydell } 1480712182d3SPeter Maydell 1481712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1482712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1483712182d3SPeter Maydell { \ 1484712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1485712182d3SPeter Maydell } 1486712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1487712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1488712182d3SPeter Maydell { \ 1489712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1490712182d3SPeter Maydell } 1491712182d3SPeter Maydell 1492712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1493712182d3SPeter Maydell { 1494712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1495712182d3SPeter Maydell } 1496712182d3SPeter Maydell 1497712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1498712182d3SPeter Maydell { 1499712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1500712182d3SPeter Maydell } 1501712182d3SPeter Maydell 1502712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1503712182d3SPeter Maydell { 1504712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1505712182d3SPeter Maydell } 1506712182d3SPeter Maydell 1507712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1508712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1509712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1510712182d3SPeter Maydell 1511712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1512712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1513712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1514712182d3SPeter Maydell 1515712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1516712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1517712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1518712182d3SPeter Maydell 1519712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1520712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1521712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1522b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1523b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1524b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1525b4a3a77bSPeter Maydell 1526b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1527b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1528b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1529b4a3a77bSPeter Maydell 1530b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1531b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1532b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1533b4a3a77bSPeter Maydell 1534b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1535b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1536b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1537968bf842SPeter Maydell 1538968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1539968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1540968bf842SPeter Maydell { 1541968bf842SPeter Maydell TCGv_i64 tmp; 1542968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1543968bf842SPeter Maydell uint64_t widen_mask = 0; 1544968bf842SPeter Maydell 1545968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1546968bf842SPeter Maydell return false; 1547968bf842SPeter Maydell } 1548968bf842SPeter Maydell 1549968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1550968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1551968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1552968bf842SPeter Maydell return false; 1553968bf842SPeter Maydell } 1554968bf842SPeter Maydell 1555968bf842SPeter Maydell if (a->vd & 1) { 1556968bf842SPeter Maydell return false; 1557968bf842SPeter Maydell } 1558968bf842SPeter Maydell 1559968bf842SPeter Maydell if (!vfp_access_check(s)) { 1560968bf842SPeter Maydell return true; 1561968bf842SPeter Maydell } 1562968bf842SPeter Maydell 1563968bf842SPeter Maydell /* 1564968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1565968bf842SPeter Maydell * than the width of the source type, so after widening the input 1566968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1567968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1568968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1569968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1570968bf842SPeter Maydell */ 1571968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1572968bf842SPeter Maydell int esize = 8 << a->size; 1573968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1574968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1575968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1576968bf842SPeter Maydell } 1577968bf842SPeter Maydell 1578a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 1579a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1580a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 1581a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 1582968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1583968bf842SPeter Maydell 1584968bf842SPeter Maydell widenfn(tmp, rm0); 1585968bf842SPeter Maydell if (a->shift != 0) { 1586968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1587968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1588968bf842SPeter Maydell } 15890aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 0, MO_64); 1590968bf842SPeter Maydell 1591968bf842SPeter Maydell widenfn(tmp, rm1); 1592968bf842SPeter Maydell if (a->shift != 0) { 1593968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1594968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1595968bf842SPeter Maydell } 15960aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 1, MO_64); 1597968bf842SPeter Maydell return true; 1598968bf842SPeter Maydell } 1599968bf842SPeter Maydell 1600968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1601968bf842SPeter Maydell { 1602448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1603968bf842SPeter Maydell gen_helper_neon_widen_s8, 1604968bf842SPeter Maydell gen_helper_neon_widen_s16, 1605968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1606968bf842SPeter Maydell }; 1607968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1608968bf842SPeter Maydell } 1609968bf842SPeter Maydell 1610968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1611968bf842SPeter Maydell { 1612448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1613968bf842SPeter Maydell gen_helper_neon_widen_u8, 1614968bf842SPeter Maydell gen_helper_neon_widen_u16, 1615968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1616968bf842SPeter Maydell }; 1617968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1618968bf842SPeter Maydell } 16193da26f11SPeter Maydell 16203da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 16217b959c58SPeter Maydell gen_helper_gvec_2_ptr *fn) 16223da26f11SPeter Maydell { 16233da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 16247b959c58SPeter Maydell int vec_size = a->q ? 16 : 8; 1625015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1626015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 16277b959c58SPeter Maydell TCGv_ptr fpst; 16283da26f11SPeter Maydell 16293da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 16303da26f11SPeter Maydell return false; 16313da26f11SPeter Maydell } 16323da26f11SPeter Maydell 16330ae715c6SPeter Maydell if (a->size == MO_16) { 16347b959c58SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 16357b959c58SPeter Maydell return false; 16367b959c58SPeter Maydell } 16377b959c58SPeter Maydell } 16387b959c58SPeter Maydell 16393da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 16403da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 16413da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 16423da26f11SPeter Maydell return false; 16433da26f11SPeter Maydell } 16443da26f11SPeter Maydell 16453da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 16463da26f11SPeter Maydell return false; 16473da26f11SPeter Maydell } 16483da26f11SPeter Maydell 16493da26f11SPeter Maydell if (!vfp_access_check(s)) { 16503da26f11SPeter Maydell return true; 16513da26f11SPeter Maydell } 16523da26f11SPeter Maydell 16530ae715c6SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 16547b959c58SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn); 16553da26f11SPeter Maydell return true; 16563da26f11SPeter Maydell } 16573da26f11SPeter Maydell 16583da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 16593da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 16603da26f11SPeter Maydell { \ 16613da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 16623da26f11SPeter Maydell } 16633da26f11SPeter Maydell 16647b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 16657b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 16667b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 16677b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) 16682c35a39eSPeter Maydell 166924018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) 167024018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) 167124018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 167224018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) 167324018cf3SPeter Maydell 16742c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 16752c35a39eSPeter Maydell GVecGen2iFn *fn) 16762c35a39eSPeter Maydell { 16772c35a39eSPeter Maydell uint64_t imm; 16782c35a39eSPeter Maydell int reg_ofs, vec_size; 16792c35a39eSPeter Maydell 16802c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 16812c35a39eSPeter Maydell return false; 16822c35a39eSPeter Maydell } 16832c35a39eSPeter Maydell 16842c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 16852c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 16862c35a39eSPeter Maydell return false; 16872c35a39eSPeter Maydell } 16882c35a39eSPeter Maydell 16892c35a39eSPeter Maydell if (a->vd & a->q) { 16902c35a39eSPeter Maydell return false; 16912c35a39eSPeter Maydell } 16922c35a39eSPeter Maydell 16932c35a39eSPeter Maydell if (!vfp_access_check(s)) { 16942c35a39eSPeter Maydell return true; 16952c35a39eSPeter Maydell } 16962c35a39eSPeter Maydell 1697015ee81aSRichard Henderson reg_ofs = neon_full_reg_offset(a->vd); 16982c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 16992c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 17002c35a39eSPeter Maydell 17012c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 17022c35a39eSPeter Maydell return true; 17032c35a39eSPeter Maydell } 17042c35a39eSPeter Maydell 17052c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 17062c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 17072c35a39eSPeter Maydell { 17082c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 17092c35a39eSPeter Maydell } 17102c35a39eSPeter Maydell 17112c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 17122c35a39eSPeter Maydell { 17132c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 17142c35a39eSPeter Maydell GVecGen2iFn *fn; 17152c35a39eSPeter Maydell 17162c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 17172c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 17182c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 17192c35a39eSPeter Maydell } else { 17202c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 17212c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 17222c35a39eSPeter Maydell return false; 17232c35a39eSPeter Maydell } 17242c35a39eSPeter Maydell fn = gen_VMOV_1r; 17252c35a39eSPeter Maydell } 17262c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 17272c35a39eSPeter Maydell } 1728b28be095SPeter Maydell 1729b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1730b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1731b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 17328aab18a2SRichard Henderson int src1_mop, int src2_mop) 1733b28be095SPeter Maydell { 1734b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1735b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1736b28be095SPeter Maydell 1737b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1738b28be095SPeter Maydell return false; 1739b28be095SPeter Maydell } 1740b28be095SPeter Maydell 1741b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1742b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1743b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1744b28be095SPeter Maydell return false; 1745b28be095SPeter Maydell } 1746b28be095SPeter Maydell 17478aab18a2SRichard Henderson if (!opfn) { 1748b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1749b28be095SPeter Maydell return false; 1750b28be095SPeter Maydell } 1751b28be095SPeter Maydell 1752fc313c64SFrédéric Pétrot if ((a->vd & 1) || (src1_mop == MO_UQ && (a->vn & 1))) { 1753b28be095SPeter Maydell return false; 1754b28be095SPeter Maydell } 1755b28be095SPeter Maydell 1756b28be095SPeter Maydell if (!vfp_access_check(s)) { 1757b28be095SPeter Maydell return true; 1758b28be095SPeter Maydell } 1759b28be095SPeter Maydell 1760b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1761b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1762b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1763b28be095SPeter Maydell 17648aab18a2SRichard Henderson if (src1_mop >= 0) { 17658aab18a2SRichard Henderson read_neon_element64(rn0_64, a->vn, 0, src1_mop); 1766b28be095SPeter Maydell } else { 1767a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1768a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1769b28be095SPeter Maydell widenfn(rn0_64, tmp); 1770b28be095SPeter Maydell } 17718aab18a2SRichard Henderson if (src2_mop >= 0) { 17728aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 0, src2_mop); 17738aab18a2SRichard Henderson } else { 17748aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 17758aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 17768aab18a2SRichard Henderson widenfn(rm_64, tmp); 17778aab18a2SRichard Henderson } 1778b28be095SPeter Maydell 1779b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1780b28be095SPeter Maydell 1781b28be095SPeter Maydell /* 1782b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1783b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1784b28be095SPeter Maydell */ 17858aab18a2SRichard Henderson if (src1_mop >= 0) { 17868aab18a2SRichard Henderson read_neon_element64(rn1_64, a->vn, 1, src1_mop); 1787b28be095SPeter Maydell } else { 1788a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1789a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 1, MO_32); 1790b28be095SPeter Maydell widenfn(rn1_64, tmp); 1791b28be095SPeter Maydell } 17928aab18a2SRichard Henderson if (src2_mop >= 0) { 17938aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 1, src2_mop); 17948aab18a2SRichard Henderson } else { 17958aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 17968aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 1, MO_32); 17978aab18a2SRichard Henderson widenfn(rm_64, tmp); 17988aab18a2SRichard Henderson } 1799b28be095SPeter Maydell 18000aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 1801b28be095SPeter Maydell 1802b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 18030aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 1804b28be095SPeter Maydell 1805b28be095SPeter Maydell return true; 1806b28be095SPeter Maydell } 1807b28be095SPeter Maydell 18088aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN) \ 1809b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1810b28be095SPeter Maydell { \ 1811b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1812b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1813b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 18148aab18a2SRichard Henderson NULL, NULL, \ 1815b28be095SPeter Maydell }; \ 1816b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1817b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1818b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1819b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1820b28be095SPeter Maydell NULL, \ 1821b28be095SPeter Maydell }; \ 18228aab18a2SRichard Henderson int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \ 18238aab18a2SRichard Henderson return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \ 1824fc313c64SFrédéric Pétrot SRC1WIDE ? MO_UQ : narrow_mop, \ 18258aab18a2SRichard Henderson narrow_mop); \ 1826b28be095SPeter Maydell } 1827b28be095SPeter Maydell 18288aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN) 18298aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0) 18308aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN) 18318aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0) 18328aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN) 18338aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0) 18348aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN) 18358aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0) 18360fa1ab03SPeter Maydell 18370fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 18380fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 18390fa1ab03SPeter Maydell { 18400fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 18410fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 18420fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 18430fa1ab03SPeter Maydell 18440fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 18450fa1ab03SPeter Maydell return false; 18460fa1ab03SPeter Maydell } 18470fa1ab03SPeter Maydell 18480fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 18490fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 18500fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 18510fa1ab03SPeter Maydell return false; 18520fa1ab03SPeter Maydell } 18530fa1ab03SPeter Maydell 18540fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 18550fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 18560fa1ab03SPeter Maydell return false; 18570fa1ab03SPeter Maydell } 18580fa1ab03SPeter Maydell 18590fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 18600fa1ab03SPeter Maydell return false; 18610fa1ab03SPeter Maydell } 18620fa1ab03SPeter Maydell 18630fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 18640fa1ab03SPeter Maydell return true; 18650fa1ab03SPeter Maydell } 18660fa1ab03SPeter Maydell 18670fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 18680fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 18690fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 18700fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 18710fa1ab03SPeter Maydell 18720aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 0, MO_64); 18730aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 0, MO_64); 18740fa1ab03SPeter Maydell 18750fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 18760fa1ab03SPeter Maydell 18770fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 18780fa1ab03SPeter Maydell 18790aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 1, MO_64); 18800aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 1, MO_64); 18810fa1ab03SPeter Maydell 18820fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 18830fa1ab03SPeter Maydell 18840fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 18850fa1ab03SPeter Maydell 1886a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 1887a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 18880fa1ab03SPeter Maydell 18890fa1ab03SPeter Maydell return true; 18900fa1ab03SPeter Maydell } 18910fa1ab03SPeter Maydell 18920fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 18930fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 18940fa1ab03SPeter Maydell { \ 18950fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 18960fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 18970fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 18980fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 18990fa1ab03SPeter Maydell NULL, \ 19000fa1ab03SPeter Maydell }; \ 19010fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 19020fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 19030fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 19040fa1ab03SPeter Maydell EXTOP, \ 19050fa1ab03SPeter Maydell NULL, \ 19060fa1ab03SPeter Maydell }; \ 19070fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 19080fa1ab03SPeter Maydell } 19090fa1ab03SPeter Maydell 19100fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 19110fa1ab03SPeter Maydell { 19120fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 19130fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 19140fa1ab03SPeter Maydell } 19150fa1ab03SPeter Maydell 19160fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 19170fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 19180fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 19190fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 1920f5b28401SPeter Maydell 1921f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 1922f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 1923f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 1924f5b28401SPeter Maydell { 1925f5b28401SPeter Maydell /* 1926f5b28401SPeter Maydell * 3-regs different lengths, long operations. 1927f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 1928f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 1929f5b28401SPeter Maydell * that result into the double-width destination. 1930f5b28401SPeter Maydell */ 1931f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 1932f5b28401SPeter Maydell TCGv_i32 rn, rm; 1933f5b28401SPeter Maydell 1934f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1935f5b28401SPeter Maydell return false; 1936f5b28401SPeter Maydell } 1937f5b28401SPeter Maydell 1938f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1939f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1940f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1941f5b28401SPeter Maydell return false; 1942f5b28401SPeter Maydell } 1943f5b28401SPeter Maydell 1944f5b28401SPeter Maydell if (!opfn) { 1945f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1946f5b28401SPeter Maydell return false; 1947f5b28401SPeter Maydell } 1948f5b28401SPeter Maydell 1949f5b28401SPeter Maydell if (a->vd & 1) { 1950f5b28401SPeter Maydell return false; 1951f5b28401SPeter Maydell } 1952f5b28401SPeter Maydell 1953f5b28401SPeter Maydell if (!vfp_access_check(s)) { 1954f5b28401SPeter Maydell return true; 1955f5b28401SPeter Maydell } 1956f5b28401SPeter Maydell 1957f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 1958f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 1959f5b28401SPeter Maydell 1960a712266fSRichard Henderson rn = tcg_temp_new_i32(); 1961a712266fSRichard Henderson rm = tcg_temp_new_i32(); 1962a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 1963a712266fSRichard Henderson read_neon_element32(rm, a->vm, 0, MO_32); 1964f5b28401SPeter Maydell opfn(rd0, rn, rm); 1965f5b28401SPeter Maydell 1966a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 1967a712266fSRichard Henderson read_neon_element32(rm, a->vm, 1, MO_32); 1968f5b28401SPeter Maydell opfn(rd1, rn, rm); 1969f5b28401SPeter Maydell 1970f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 1971f5b28401SPeter Maydell if (accfn) { 1972f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 19730aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 0, MO_64); 19749f1a5f93SRichard Henderson accfn(rd0, tmp, rd0); 19750aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 1, MO_64); 19769f1a5f93SRichard Henderson accfn(rd1, tmp, rd1); 1977f5b28401SPeter Maydell } 1978f5b28401SPeter Maydell 19799f1a5f93SRichard Henderson write_neon_element64(rd0, a->vd, 0, MO_64); 19809f1a5f93SRichard Henderson write_neon_element64(rd1, a->vd, 1, MO_64); 1981f5b28401SPeter Maydell 1982f5b28401SPeter Maydell return true; 1983f5b28401SPeter Maydell } 1984f5b28401SPeter Maydell 1985f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 1986f5b28401SPeter Maydell { 1987f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 1988f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 1989f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 1990f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 1991f5b28401SPeter Maydell NULL, 1992f5b28401SPeter Maydell }; 1993f5b28401SPeter Maydell 1994f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 1995f5b28401SPeter Maydell } 1996f5b28401SPeter Maydell 1997f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 1998f5b28401SPeter Maydell { 1999f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2000f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2001f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2002f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2003f5b28401SPeter Maydell NULL, 2004f5b28401SPeter Maydell }; 2005f5b28401SPeter Maydell 2006f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2007f5b28401SPeter Maydell } 2008f5b28401SPeter Maydell 2009f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2010f5b28401SPeter Maydell { 2011f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2012f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2013f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2014f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2015f5b28401SPeter Maydell NULL, 2016f5b28401SPeter Maydell }; 2017f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2018f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2019f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2020f5b28401SPeter Maydell tcg_gen_add_i64, 2021f5b28401SPeter Maydell NULL, 2022f5b28401SPeter Maydell }; 2023f5b28401SPeter Maydell 2024f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2025f5b28401SPeter Maydell } 2026f5b28401SPeter Maydell 2027f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2028f5b28401SPeter Maydell { 2029f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2030f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2031f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2032f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2033f5b28401SPeter Maydell NULL, 2034f5b28401SPeter Maydell }; 2035f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2036f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2037f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2038f5b28401SPeter Maydell tcg_gen_add_i64, 2039f5b28401SPeter Maydell NULL, 2040f5b28401SPeter Maydell }; 2041f5b28401SPeter Maydell 2042f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2043f5b28401SPeter Maydell } 20443a1d9eb0SPeter Maydell 20453a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 20463a1d9eb0SPeter Maydell { 20473a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 20483a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 20493a1d9eb0SPeter Maydell 20503a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 20513a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 20523a1d9eb0SPeter Maydell } 20533a1d9eb0SPeter Maydell 20543a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 20553a1d9eb0SPeter Maydell { 20563a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 20573a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 20583a1d9eb0SPeter Maydell 20593a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 20603a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 20613a1d9eb0SPeter Maydell } 20623a1d9eb0SPeter Maydell 20633a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 20643a1d9eb0SPeter Maydell { 20653a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 20663a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 20673a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 20683a1d9eb0SPeter Maydell gen_mull_s32, 20693a1d9eb0SPeter Maydell NULL, 20703a1d9eb0SPeter Maydell }; 20713a1d9eb0SPeter Maydell 20723a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 20733a1d9eb0SPeter Maydell } 20743a1d9eb0SPeter Maydell 20753a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 20763a1d9eb0SPeter Maydell { 20773a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 20783a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 20793a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 20803a1d9eb0SPeter Maydell gen_mull_u32, 20813a1d9eb0SPeter Maydell NULL, 20823a1d9eb0SPeter Maydell }; 20833a1d9eb0SPeter Maydell 20843a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 20853a1d9eb0SPeter Maydell } 20863a1d9eb0SPeter Maydell 20873a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 20883a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 20893a1d9eb0SPeter Maydell { \ 20903a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 20913a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 20923a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 20933a1d9eb0SPeter Maydell gen_##MULL##32, \ 20943a1d9eb0SPeter Maydell NULL, \ 20953a1d9eb0SPeter Maydell }; \ 20963a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 20973a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 20983a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 20993a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 21003a1d9eb0SPeter Maydell NULL, \ 21013a1d9eb0SPeter Maydell }; \ 21023a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 21033a1d9eb0SPeter Maydell } 21043a1d9eb0SPeter Maydell 21053a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 21063a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 21073a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 21083a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 21099546ca59SPeter Maydell 21109546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21119546ca59SPeter Maydell { 21129546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 2113ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s32(rd, tcg_env, rd, rd); 21149546ca59SPeter Maydell } 21159546ca59SPeter Maydell 21169546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21179546ca59SPeter Maydell { 21189546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 2119ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s64(rd, tcg_env, rd, rd); 21209546ca59SPeter Maydell } 21219546ca59SPeter Maydell 21229546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 21239546ca59SPeter Maydell { 21249546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21259546ca59SPeter Maydell NULL, 21269546ca59SPeter Maydell gen_VQDMULL_16, 21279546ca59SPeter Maydell gen_VQDMULL_32, 21289546ca59SPeter Maydell NULL, 21299546ca59SPeter Maydell }; 21309546ca59SPeter Maydell 21319546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21329546ca59SPeter Maydell } 21339546ca59SPeter Maydell 21349546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21359546ca59SPeter Maydell { 2136ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm); 21379546ca59SPeter Maydell } 21389546ca59SPeter Maydell 21399546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21409546ca59SPeter Maydell { 2141ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm); 21429546ca59SPeter Maydell } 21439546ca59SPeter Maydell 21449546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 21459546ca59SPeter Maydell { 21469546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21479546ca59SPeter Maydell NULL, 21489546ca59SPeter Maydell gen_VQDMULL_16, 21499546ca59SPeter Maydell gen_VQDMULL_32, 21509546ca59SPeter Maydell NULL, 21519546ca59SPeter Maydell }; 21529546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 21539546ca59SPeter Maydell NULL, 21549546ca59SPeter Maydell gen_VQDMLAL_acc_16, 21559546ca59SPeter Maydell gen_VQDMLAL_acc_32, 21569546ca59SPeter Maydell NULL, 21579546ca59SPeter Maydell }; 21589546ca59SPeter Maydell 21599546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 21609546ca59SPeter Maydell } 21619546ca59SPeter Maydell 21629546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21639546ca59SPeter Maydell { 21649546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 2165ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s32(rd, tcg_env, rn, rm); 21669546ca59SPeter Maydell } 21679546ca59SPeter Maydell 21689546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21699546ca59SPeter Maydell { 21709546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 2171ad75a51eSRichard Henderson gen_helper_neon_addl_saturate_s64(rd, tcg_env, rn, rm); 21729546ca59SPeter Maydell } 21739546ca59SPeter Maydell 21749546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 21759546ca59SPeter Maydell { 21769546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21779546ca59SPeter Maydell NULL, 21789546ca59SPeter Maydell gen_VQDMULL_16, 21799546ca59SPeter Maydell gen_VQDMULL_32, 21809546ca59SPeter Maydell NULL, 21819546ca59SPeter Maydell }; 21829546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 21839546ca59SPeter Maydell NULL, 21849546ca59SPeter Maydell gen_VQDMLSL_acc_16, 21859546ca59SPeter Maydell gen_VQDMLSL_acc_32, 21869546ca59SPeter Maydell NULL, 21879546ca59SPeter Maydell }; 21889546ca59SPeter Maydell 21899546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 21909546ca59SPeter Maydell } 219118fb58d5SPeter Maydell 219218fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 219318fb58d5SPeter Maydell { 219418fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 219518fb58d5SPeter Maydell 219618fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 219718fb58d5SPeter Maydell return false; 219818fb58d5SPeter Maydell } 219918fb58d5SPeter Maydell 220018fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 220118fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 220218fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 220318fb58d5SPeter Maydell return false; 220418fb58d5SPeter Maydell } 220518fb58d5SPeter Maydell 220618fb58d5SPeter Maydell if (a->vd & 1) { 220718fb58d5SPeter Maydell return false; 220818fb58d5SPeter Maydell } 220918fb58d5SPeter Maydell 221018fb58d5SPeter Maydell switch (a->size) { 221118fb58d5SPeter Maydell case 0: 221218fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 221318fb58d5SPeter Maydell break; 221418fb58d5SPeter Maydell case 2: 221518fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 221618fb58d5SPeter Maydell return false; 221718fb58d5SPeter Maydell } 221818fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 221918fb58d5SPeter Maydell break; 222018fb58d5SPeter Maydell default: 222118fb58d5SPeter Maydell return false; 222218fb58d5SPeter Maydell } 222318fb58d5SPeter Maydell 222418fb58d5SPeter Maydell if (!vfp_access_check(s)) { 222518fb58d5SPeter Maydell return true; 222618fb58d5SPeter Maydell } 222718fb58d5SPeter Maydell 2228015ee81aSRichard Henderson tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd), 2229015ee81aSRichard Henderson neon_full_reg_offset(a->vn), 2230015ee81aSRichard Henderson neon_full_reg_offset(a->vm), 223118fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 223218fb58d5SPeter Maydell return true; 223318fb58d5SPeter Maydell } 223496fc80f5SPeter Maydell 223596fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 223696fc80f5SPeter Maydell { 223796fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 223896fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 223996fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 224096fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 224196fc80f5SPeter Maydell } 224296fc80f5SPeter Maydell 224396fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 224496fc80f5SPeter Maydell { 224596fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 224696fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 224796fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 224896fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 224996fc80f5SPeter Maydell } 225096fc80f5SPeter Maydell 225196fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 225296fc80f5SPeter Maydell { 2253a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 2254a712266fSRichard Henderson if (size == MO_16) { 2255a712266fSRichard Henderson read_neon_element32(tmp, reg & 7, reg >> 4, MO_32); 225696fc80f5SPeter Maydell if (reg & 8) { 225796fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 225896fc80f5SPeter Maydell } else { 225996fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 226096fc80f5SPeter Maydell } 226196fc80f5SPeter Maydell } else { 2262a712266fSRichard Henderson read_neon_element32(tmp, reg & 15, reg >> 4, MO_32); 226396fc80f5SPeter Maydell } 226496fc80f5SPeter Maydell return tmp; 226596fc80f5SPeter Maydell } 226696fc80f5SPeter Maydell 226796fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 226896fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 226996fc80f5SPeter Maydell { 227096fc80f5SPeter Maydell /* 227196fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 227296fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 227396fc80f5SPeter Maydell * perform an accumulation operation of that result into the 227496fc80f5SPeter Maydell * destination. 227596fc80f5SPeter Maydell */ 2276a712266fSRichard Henderson TCGv_i32 scalar, tmp; 227796fc80f5SPeter Maydell int pass; 227896fc80f5SPeter Maydell 227996fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 228096fc80f5SPeter Maydell return false; 228196fc80f5SPeter Maydell } 228296fc80f5SPeter Maydell 228396fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 228496fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 228596fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 228696fc80f5SPeter Maydell return false; 228796fc80f5SPeter Maydell } 228896fc80f5SPeter Maydell 228996fc80f5SPeter Maydell if (!opfn) { 229096fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 229196fc80f5SPeter Maydell return false; 229296fc80f5SPeter Maydell } 229396fc80f5SPeter Maydell 229496fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 229596fc80f5SPeter Maydell return false; 229696fc80f5SPeter Maydell } 229796fc80f5SPeter Maydell 229896fc80f5SPeter Maydell if (!vfp_access_check(s)) { 229996fc80f5SPeter Maydell return true; 230096fc80f5SPeter Maydell } 230196fc80f5SPeter Maydell 230296fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2303a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 230496fc80f5SPeter Maydell 230596fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2306a712266fSRichard Henderson read_neon_element32(tmp, a->vn, pass, MO_32); 230796fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 230896fc80f5SPeter Maydell if (accfn) { 2309a712266fSRichard Henderson TCGv_i32 rd = tcg_temp_new_i32(); 2310a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 231196fc80f5SPeter Maydell accfn(tmp, rd, tmp); 231296fc80f5SPeter Maydell } 2313a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 231496fc80f5SPeter Maydell } 231596fc80f5SPeter Maydell return true; 231696fc80f5SPeter Maydell } 231796fc80f5SPeter Maydell 231896fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 231996fc80f5SPeter Maydell { 232096fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 232196fc80f5SPeter Maydell NULL, 232296fc80f5SPeter Maydell gen_helper_neon_mul_u16, 232396fc80f5SPeter Maydell tcg_gen_mul_i32, 232496fc80f5SPeter Maydell NULL, 232596fc80f5SPeter Maydell }; 232696fc80f5SPeter Maydell 232796fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 232896fc80f5SPeter Maydell } 232996fc80f5SPeter Maydell 233096fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 233196fc80f5SPeter Maydell { 233296fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 233396fc80f5SPeter Maydell NULL, 233496fc80f5SPeter Maydell gen_helper_neon_mul_u16, 233596fc80f5SPeter Maydell tcg_gen_mul_i32, 233696fc80f5SPeter Maydell NULL, 233796fc80f5SPeter Maydell }; 233896fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 233996fc80f5SPeter Maydell NULL, 234096fc80f5SPeter Maydell gen_helper_neon_add_u16, 234196fc80f5SPeter Maydell tcg_gen_add_i32, 234296fc80f5SPeter Maydell NULL, 234396fc80f5SPeter Maydell }; 234496fc80f5SPeter Maydell 234596fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 234696fc80f5SPeter Maydell } 234796fc80f5SPeter Maydell 234896fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 234996fc80f5SPeter Maydell { 235096fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 235196fc80f5SPeter Maydell NULL, 235296fc80f5SPeter Maydell gen_helper_neon_mul_u16, 235396fc80f5SPeter Maydell tcg_gen_mul_i32, 235496fc80f5SPeter Maydell NULL, 235596fc80f5SPeter Maydell }; 235696fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 235796fc80f5SPeter Maydell NULL, 235896fc80f5SPeter Maydell gen_helper_neon_sub_u16, 235996fc80f5SPeter Maydell tcg_gen_sub_i32, 236096fc80f5SPeter Maydell NULL, 236196fc80f5SPeter Maydell }; 236296fc80f5SPeter Maydell 236396fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 236496fc80f5SPeter Maydell } 236585ac9aefSPeter Maydell 2366fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, 2367fc8ae790SPeter Maydell gen_helper_gvec_3_ptr *fn) 2368fc8ae790SPeter Maydell { 2369fc8ae790SPeter Maydell /* Two registers and a scalar, using gvec */ 2370fc8ae790SPeter Maydell int vec_size = a->q ? 16 : 8; 2371015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 2372015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 2373fc8ae790SPeter Maydell int rm_ofs; 2374fc8ae790SPeter Maydell int idx; 2375fc8ae790SPeter Maydell TCGv_ptr fpstatus; 2376fc8ae790SPeter Maydell 2377fc8ae790SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2378fc8ae790SPeter Maydell return false; 2379fc8ae790SPeter Maydell } 2380fc8ae790SPeter Maydell 2381fc8ae790SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2382fc8ae790SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2383fc8ae790SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2384fc8ae790SPeter Maydell return false; 2385fc8ae790SPeter Maydell } 2386fc8ae790SPeter Maydell 2387fc8ae790SPeter Maydell if (!fn) { 2388fc8ae790SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2389fc8ae790SPeter Maydell return false; 2390fc8ae790SPeter Maydell } 2391fc8ae790SPeter Maydell 2392fc8ae790SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2393fc8ae790SPeter Maydell return false; 2394fc8ae790SPeter Maydell } 2395fc8ae790SPeter Maydell 2396fc8ae790SPeter Maydell if (!vfp_access_check(s)) { 2397fc8ae790SPeter Maydell return true; 2398fc8ae790SPeter Maydell } 2399fc8ae790SPeter Maydell 2400fc8ae790SPeter Maydell /* a->vm is M:Vm, which encodes both register and index */ 2401fc8ae790SPeter Maydell idx = extract32(a->vm, a->size + 2, 2); 2402fc8ae790SPeter Maydell a->vm = extract32(a->vm, 0, a->size + 2); 2403015ee81aSRichard Henderson rm_ofs = neon_full_reg_offset(a->vm); 2404fc8ae790SPeter Maydell 2405fc8ae790SPeter Maydell fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD); 2406fc8ae790SPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus, 2407fc8ae790SPeter Maydell vec_size, vec_size, idx, fn); 2408fc8ae790SPeter Maydell return true; 2409fc8ae790SPeter Maydell } 2410fc8ae790SPeter Maydell 2411fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC) \ 2412fc8ae790SPeter Maydell static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \ 241385ac9aefSPeter Maydell { \ 2414fc8ae790SPeter Maydell static gen_helper_gvec_3_ptr * const opfn[] = { \ 2415fc8ae790SPeter Maydell NULL, \ 2416fc8ae790SPeter Maydell gen_helper_##FUNC##_h, \ 2417fc8ae790SPeter Maydell gen_helper_##FUNC##_s, \ 2418fc8ae790SPeter Maydell NULL, \ 2419fc8ae790SPeter Maydell }; \ 2420fc8ae790SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \ 2421fc8ae790SPeter Maydell return false; \ 2422fc8ae790SPeter Maydell } \ 2423fc8ae790SPeter Maydell return do_2scalar_fp_vec(s, a, opfn[a->size]); \ 242485ac9aefSPeter Maydell } 242585ac9aefSPeter Maydell 2426fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx) 2427fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx) 2428fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx) 2429b2fc7be9SPeter Maydell 2430b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2431b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2432b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2433b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2434b2fc7be9SPeter Maydell 2435b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2436b2fc7be9SPeter Maydell { 2437b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2438b2fc7be9SPeter Maydell NULL, 2439b2fc7be9SPeter Maydell gen_VQDMULH_16, 2440b2fc7be9SPeter Maydell gen_VQDMULH_32, 2441b2fc7be9SPeter Maydell NULL, 2442b2fc7be9SPeter Maydell }; 2443b2fc7be9SPeter Maydell 2444b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2445b2fc7be9SPeter Maydell } 2446b2fc7be9SPeter Maydell 2447b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2448b2fc7be9SPeter Maydell { 2449b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2450b2fc7be9SPeter Maydell NULL, 2451b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2452b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2453b2fc7be9SPeter Maydell NULL, 2454b2fc7be9SPeter Maydell }; 2455b2fc7be9SPeter Maydell 2456b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2457b2fc7be9SPeter Maydell } 2458aa318f5bSPeter Maydell 2459aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2460aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2461aa318f5bSPeter Maydell { 2462aa318f5bSPeter Maydell /* 2463aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2464aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2465aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2466aa318f5bSPeter Maydell */ 2467a712266fSRichard Henderson TCGv_i32 scalar, rn, rd; 2468aa318f5bSPeter Maydell int pass; 2469aa318f5bSPeter Maydell 2470aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2471aa318f5bSPeter Maydell return false; 2472aa318f5bSPeter Maydell } 2473aa318f5bSPeter Maydell 2474aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2475aa318f5bSPeter Maydell return false; 2476aa318f5bSPeter Maydell } 2477aa318f5bSPeter Maydell 2478aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2479aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2480aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2481aa318f5bSPeter Maydell return false; 2482aa318f5bSPeter Maydell } 2483aa318f5bSPeter Maydell 2484aa318f5bSPeter Maydell if (!opfn) { 2485aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2486aa318f5bSPeter Maydell return false; 2487aa318f5bSPeter Maydell } 2488aa318f5bSPeter Maydell 2489aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2490aa318f5bSPeter Maydell return false; 2491aa318f5bSPeter Maydell } 2492aa318f5bSPeter Maydell 2493aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2494aa318f5bSPeter Maydell return true; 2495aa318f5bSPeter Maydell } 2496aa318f5bSPeter Maydell 2497aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2498a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2499a712266fSRichard Henderson rd = tcg_temp_new_i32(); 2500aa318f5bSPeter Maydell 2501aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2502a712266fSRichard Henderson read_neon_element32(rn, a->vn, pass, MO_32); 2503a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 2504ad75a51eSRichard Henderson opfn(rd, tcg_env, rn, scalar, rd); 2505a712266fSRichard Henderson write_neon_element32(rd, a->vd, pass, MO_32); 2506aa318f5bSPeter Maydell } 2507aa318f5bSPeter Maydell return true; 2508aa318f5bSPeter Maydell } 2509aa318f5bSPeter Maydell 2510aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2511aa318f5bSPeter Maydell { 2512aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2513aa318f5bSPeter Maydell NULL, 2514aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2515aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2516aa318f5bSPeter Maydell NULL, 2517aa318f5bSPeter Maydell }; 2518aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2519aa318f5bSPeter Maydell } 2520aa318f5bSPeter Maydell 2521aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2522aa318f5bSPeter Maydell { 2523aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2524aa318f5bSPeter Maydell NULL, 2525aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2526aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2527aa318f5bSPeter Maydell NULL, 2528aa318f5bSPeter Maydell }; 2529aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2530aa318f5bSPeter Maydell } 253177e576a9SPeter Maydell 253277e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 253377e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 253477e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 253577e576a9SPeter Maydell { 253677e576a9SPeter Maydell /* 253777e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 253877e576a9SPeter Maydell * operation on the input elements and the scalar which produces 253977e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 254077e576a9SPeter Maydell * operation of that result into the destination. 254177e576a9SPeter Maydell */ 254277e576a9SPeter Maydell TCGv_i32 scalar, rn; 254377e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 254477e576a9SPeter Maydell 254577e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 254677e576a9SPeter Maydell return false; 254777e576a9SPeter Maydell } 254877e576a9SPeter Maydell 254977e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 255077e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 255177e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 255277e576a9SPeter Maydell return false; 255377e576a9SPeter Maydell } 255477e576a9SPeter Maydell 255577e576a9SPeter Maydell if (!opfn) { 255677e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 255777e576a9SPeter Maydell return false; 255877e576a9SPeter Maydell } 255977e576a9SPeter Maydell 256077e576a9SPeter Maydell if (a->vd & 1) { 256177e576a9SPeter Maydell return false; 256277e576a9SPeter Maydell } 256377e576a9SPeter Maydell 256477e576a9SPeter Maydell if (!vfp_access_check(s)) { 256577e576a9SPeter Maydell return true; 256677e576a9SPeter Maydell } 256777e576a9SPeter Maydell 256877e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 256977e576a9SPeter Maydell 257077e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 2571a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2572a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 257377e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 257477e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 257577e576a9SPeter Maydell 2576a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 257777e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 257877e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 257977e576a9SPeter Maydell 258077e576a9SPeter Maydell if (accfn) { 258177e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 25820aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 0, MO_64); 25839f1a5f93SRichard Henderson accfn(rn0_64, t64, rn0_64); 25840aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 1, MO_64); 25859f1a5f93SRichard Henderson accfn(rn1_64, t64, rn1_64); 25869f1a5f93SRichard Henderson } 25879f1a5f93SRichard Henderson 25880aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 25890aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 259077e576a9SPeter Maydell return true; 259177e576a9SPeter Maydell } 259277e576a9SPeter Maydell 259377e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 259477e576a9SPeter Maydell { 259577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 259677e576a9SPeter Maydell NULL, 259777e576a9SPeter Maydell gen_helper_neon_mull_s16, 259877e576a9SPeter Maydell gen_mull_s32, 259977e576a9SPeter Maydell NULL, 260077e576a9SPeter Maydell }; 260177e576a9SPeter Maydell 260277e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 260377e576a9SPeter Maydell } 260477e576a9SPeter Maydell 260577e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 260677e576a9SPeter Maydell { 260777e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 260877e576a9SPeter Maydell NULL, 260977e576a9SPeter Maydell gen_helper_neon_mull_u16, 261077e576a9SPeter Maydell gen_mull_u32, 261177e576a9SPeter Maydell NULL, 261277e576a9SPeter Maydell }; 261377e576a9SPeter Maydell 261477e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 261577e576a9SPeter Maydell } 261677e576a9SPeter Maydell 261777e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 261877e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 261977e576a9SPeter Maydell { \ 262077e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 262177e576a9SPeter Maydell NULL, \ 262277e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 262377e576a9SPeter Maydell gen_##MULL##32, \ 262477e576a9SPeter Maydell NULL, \ 262577e576a9SPeter Maydell }; \ 262677e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 262777e576a9SPeter Maydell NULL, \ 262877e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 262977e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 263077e576a9SPeter Maydell NULL, \ 263177e576a9SPeter Maydell }; \ 263277e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 263377e576a9SPeter Maydell } 263477e576a9SPeter Maydell 263577e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 263677e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 263777e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 263877e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 263977e576a9SPeter Maydell 264077e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 264177e576a9SPeter Maydell { 264277e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 264377e576a9SPeter Maydell NULL, 264477e576a9SPeter Maydell gen_VQDMULL_16, 264577e576a9SPeter Maydell gen_VQDMULL_32, 264677e576a9SPeter Maydell NULL, 264777e576a9SPeter Maydell }; 264877e576a9SPeter Maydell 264977e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 265077e576a9SPeter Maydell } 265177e576a9SPeter Maydell 265277e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 265377e576a9SPeter Maydell { 265477e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 265577e576a9SPeter Maydell NULL, 265677e576a9SPeter Maydell gen_VQDMULL_16, 265777e576a9SPeter Maydell gen_VQDMULL_32, 265877e576a9SPeter Maydell NULL, 265977e576a9SPeter Maydell }; 266077e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 266177e576a9SPeter Maydell NULL, 266277e576a9SPeter Maydell gen_VQDMLAL_acc_16, 266377e576a9SPeter Maydell gen_VQDMLAL_acc_32, 266477e576a9SPeter Maydell NULL, 266577e576a9SPeter Maydell }; 266677e576a9SPeter Maydell 266777e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 266877e576a9SPeter Maydell } 266977e576a9SPeter Maydell 267077e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 267177e576a9SPeter Maydell { 267277e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 267377e576a9SPeter Maydell NULL, 267477e576a9SPeter Maydell gen_VQDMULL_16, 267577e576a9SPeter Maydell gen_VQDMULL_32, 267677e576a9SPeter Maydell NULL, 267777e576a9SPeter Maydell }; 267877e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 267977e576a9SPeter Maydell NULL, 268077e576a9SPeter Maydell gen_VQDMLSL_acc_16, 268177e576a9SPeter Maydell gen_VQDMLSL_acc_32, 268277e576a9SPeter Maydell NULL, 268377e576a9SPeter Maydell }; 268477e576a9SPeter Maydell 268577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 268677e576a9SPeter Maydell } 26870aad761fSPeter Maydell 26880aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 26890aad761fSPeter Maydell { 26900aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 26910aad761fSPeter Maydell return false; 26920aad761fSPeter Maydell } 26930aad761fSPeter Maydell 26940aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 26950aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 26960aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 26970aad761fSPeter Maydell return false; 26980aad761fSPeter Maydell } 26990aad761fSPeter Maydell 27000aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 27010aad761fSPeter Maydell return false; 27020aad761fSPeter Maydell } 27030aad761fSPeter Maydell 27040aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 27050aad761fSPeter Maydell return false; 27060aad761fSPeter Maydell } 27070aad761fSPeter Maydell 27080aad761fSPeter Maydell if (!vfp_access_check(s)) { 27090aad761fSPeter Maydell return true; 27100aad761fSPeter Maydell } 27110aad761fSPeter Maydell 27120aad761fSPeter Maydell if (!a->q) { 27130aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 27140aad761fSPeter Maydell TCGv_i64 left, right, dest; 27150aad761fSPeter Maydell 27160aad761fSPeter Maydell left = tcg_temp_new_i64(); 27170aad761fSPeter Maydell right = tcg_temp_new_i64(); 27180aad761fSPeter Maydell dest = tcg_temp_new_i64(); 27190aad761fSPeter Maydell 27200aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 27210aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 27220aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 27230aa8e700SRichard Henderson write_neon_element64(dest, a->vd, 0, MO_64); 27240aad761fSPeter Maydell } else { 27250aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 27260aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 27270aad761fSPeter Maydell 27280aad761fSPeter Maydell left = tcg_temp_new_i64(); 27290aad761fSPeter Maydell middle = tcg_temp_new_i64(); 27300aad761fSPeter Maydell right = tcg_temp_new_i64(); 27310aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 27320aad761fSPeter Maydell destright = tcg_temp_new_i64(); 27330aad761fSPeter Maydell 27340aad761fSPeter Maydell if (a->imm < 8) { 27350aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 27360aa8e700SRichard Henderson read_neon_element64(middle, a->vn, 1, MO_64); 27370aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 27380aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 27390aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 27400aad761fSPeter Maydell } else { 27410aa8e700SRichard Henderson read_neon_element64(right, a->vn, 1, MO_64); 27420aa8e700SRichard Henderson read_neon_element64(middle, a->vm, 0, MO_64); 27430aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 27440aa8e700SRichard Henderson read_neon_element64(left, a->vm, 1, MO_64); 27450aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 27460aad761fSPeter Maydell } 27470aad761fSPeter Maydell 27480aa8e700SRichard Henderson write_neon_element64(destright, a->vd, 0, MO_64); 27490aa8e700SRichard Henderson write_neon_element64(destleft, a->vd, 1, MO_64); 27500aad761fSPeter Maydell } 27510aad761fSPeter Maydell return true; 27520aad761fSPeter Maydell } 275354e96c74SPeter Maydell 275454e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 275554e96c74SPeter Maydell { 2756604cef3eSRichard Henderson TCGv_i64 val, def; 2757604cef3eSRichard Henderson TCGv_i32 desc; 275854e96c74SPeter Maydell 275954e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 276054e96c74SPeter Maydell return false; 276154e96c74SPeter Maydell } 276254e96c74SPeter Maydell 276354e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 276454e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 276554e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 276654e96c74SPeter Maydell return false; 276754e96c74SPeter Maydell } 276854e96c74SPeter Maydell 2769604cef3eSRichard Henderson if ((a->vn + a->len + 1) > 32) { 277054e96c74SPeter Maydell /* 277154e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 277254e96c74SPeter Maydell * helper function running off the end of the register file. 277354e96c74SPeter Maydell */ 277454e96c74SPeter Maydell return false; 277554e96c74SPeter Maydell } 2776a712266fSRichard Henderson 2777b6c56c8aSPeter Maydell if (!vfp_access_check(s)) { 2778b6c56c8aSPeter Maydell return true; 2779b6c56c8aSPeter Maydell } 2780b6c56c8aSPeter Maydell 2781d9b47e97SRichard Henderson desc = tcg_constant_i32((a->vn << 2) | a->len); 2782604cef3eSRichard Henderson def = tcg_temp_new_i64(); 278354e96c74SPeter Maydell if (a->op) { 2784604cef3eSRichard Henderson read_neon_element64(def, a->vd, 0, MO_64); 278554e96c74SPeter Maydell } else { 2786604cef3eSRichard Henderson tcg_gen_movi_i64(def, 0); 278754e96c74SPeter Maydell } 2788604cef3eSRichard Henderson val = tcg_temp_new_i64(); 2789604cef3eSRichard Henderson read_neon_element64(val, a->vm, 0, MO_64); 2790a712266fSRichard Henderson 2791ad75a51eSRichard Henderson gen_helper_neon_tbl(val, tcg_env, desc, val, def); 2792604cef3eSRichard Henderson write_neon_element64(val, a->vd, 0, MO_64); 279354e96c74SPeter Maydell return true; 279454e96c74SPeter Maydell } 27959aaa23c2SPeter Maydell 27969aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 27979aaa23c2SPeter Maydell { 27989aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 27999aaa23c2SPeter Maydell return false; 28009aaa23c2SPeter Maydell } 28019aaa23c2SPeter Maydell 28029aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28039aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28049aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 28059aaa23c2SPeter Maydell return false; 28069aaa23c2SPeter Maydell } 28079aaa23c2SPeter Maydell 28089aaa23c2SPeter Maydell if (a->vd & a->q) { 28099aaa23c2SPeter Maydell return false; 28109aaa23c2SPeter Maydell } 28119aaa23c2SPeter Maydell 28129aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 28139aaa23c2SPeter Maydell return true; 28149aaa23c2SPeter Maydell } 28159aaa23c2SPeter Maydell 2816015ee81aSRichard Henderson tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd), 28179aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 28189aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 28199aaa23c2SPeter Maydell return true; 28209aaa23c2SPeter Maydell } 2821353d2b85SPeter Maydell 2822353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 2823353d2b85SPeter Maydell { 2824353d2b85SPeter Maydell int pass, half; 2825a712266fSRichard Henderson TCGv_i32 tmp[2]; 2826353d2b85SPeter Maydell 2827353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2828353d2b85SPeter Maydell return false; 2829353d2b85SPeter Maydell } 2830353d2b85SPeter Maydell 2831353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2832353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2833353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 2834353d2b85SPeter Maydell return false; 2835353d2b85SPeter Maydell } 2836353d2b85SPeter Maydell 2837353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 2838353d2b85SPeter Maydell return false; 2839353d2b85SPeter Maydell } 2840353d2b85SPeter Maydell 2841353d2b85SPeter Maydell if (a->size == 3) { 2842353d2b85SPeter Maydell return false; 2843353d2b85SPeter Maydell } 2844353d2b85SPeter Maydell 2845353d2b85SPeter Maydell if (!vfp_access_check(s)) { 2846353d2b85SPeter Maydell return true; 2847353d2b85SPeter Maydell } 2848353d2b85SPeter Maydell 2849a712266fSRichard Henderson tmp[0] = tcg_temp_new_i32(); 2850a712266fSRichard Henderson tmp[1] = tcg_temp_new_i32(); 2851353d2b85SPeter Maydell 2852a712266fSRichard Henderson for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 2853353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 2854a712266fSRichard Henderson read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32); 2855353d2b85SPeter Maydell switch (a->size) { 2856353d2b85SPeter Maydell case 0: 2857353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 2858353d2b85SPeter Maydell break; 2859353d2b85SPeter Maydell case 1: 28608ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 2861353d2b85SPeter Maydell break; 2862353d2b85SPeter Maydell case 2: 2863353d2b85SPeter Maydell break; 2864353d2b85SPeter Maydell default: 2865353d2b85SPeter Maydell g_assert_not_reached(); 2866353d2b85SPeter Maydell } 2867353d2b85SPeter Maydell } 2868a712266fSRichard Henderson write_neon_element32(tmp[1], a->vd, pass * 2, MO_32); 2869a712266fSRichard Henderson write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32); 2870353d2b85SPeter Maydell } 2871353d2b85SPeter Maydell return true; 2872353d2b85SPeter Maydell } 28736106af3aSPeter Maydell 28746106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 28756106af3aSPeter Maydell NeonGenWidenFn *widenfn, 28766106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 28776106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 28786106af3aSPeter Maydell { 28796106af3aSPeter Maydell /* 28806106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 28816106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 28826106af3aSPeter Maydell * into the destination with the accfn. 28836106af3aSPeter Maydell */ 28846106af3aSPeter Maydell int pass; 28856106af3aSPeter Maydell 28866106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 28876106af3aSPeter Maydell return false; 28886106af3aSPeter Maydell } 28896106af3aSPeter Maydell 28906106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28916106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28926106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 28936106af3aSPeter Maydell return false; 28946106af3aSPeter Maydell } 28956106af3aSPeter Maydell 28966106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 28976106af3aSPeter Maydell return false; 28986106af3aSPeter Maydell } 28996106af3aSPeter Maydell 29006106af3aSPeter Maydell if (!widenfn) { 29016106af3aSPeter Maydell return false; 29026106af3aSPeter Maydell } 29036106af3aSPeter Maydell 29046106af3aSPeter Maydell if (!vfp_access_check(s)) { 29056106af3aSPeter Maydell return true; 29066106af3aSPeter Maydell } 29076106af3aSPeter Maydell 29086106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 29096106af3aSPeter Maydell TCGv_i32 tmp; 29106106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 29116106af3aSPeter Maydell 29126106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 29136106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 29146106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 2915a712266fSRichard Henderson 2916a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 2917a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2, MO_32); 29186106af3aSPeter Maydell widenfn(rm0_64, tmp); 2919a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32); 29206106af3aSPeter Maydell widenfn(rm1_64, tmp); 2921a712266fSRichard Henderson 29226106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 29236106af3aSPeter Maydell 29246106af3aSPeter Maydell if (accfn) { 29256106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 29260aa8e700SRichard Henderson read_neon_element64(tmp64, a->vd, pass, MO_64); 29276106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 29286106af3aSPeter Maydell } 29290aa8e700SRichard Henderson write_neon_element64(rd_64, a->vd, pass, MO_64); 29306106af3aSPeter Maydell } 29316106af3aSPeter Maydell return true; 29326106af3aSPeter Maydell } 29336106af3aSPeter Maydell 29346106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 29356106af3aSPeter Maydell { 29366106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 29376106af3aSPeter Maydell gen_helper_neon_widen_s8, 29386106af3aSPeter Maydell gen_helper_neon_widen_s16, 29396106af3aSPeter Maydell tcg_gen_ext_i32_i64, 29406106af3aSPeter Maydell NULL, 29416106af3aSPeter Maydell }; 29426106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 29436106af3aSPeter Maydell gen_helper_neon_paddl_u16, 29446106af3aSPeter Maydell gen_helper_neon_paddl_u32, 29456106af3aSPeter Maydell tcg_gen_add_i64, 29466106af3aSPeter Maydell NULL, 29476106af3aSPeter Maydell }; 29486106af3aSPeter Maydell 29496106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 29506106af3aSPeter Maydell } 29516106af3aSPeter Maydell 29526106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 29536106af3aSPeter Maydell { 29546106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 29556106af3aSPeter Maydell gen_helper_neon_widen_u8, 29566106af3aSPeter Maydell gen_helper_neon_widen_u16, 29576106af3aSPeter Maydell tcg_gen_extu_i32_i64, 29586106af3aSPeter Maydell NULL, 29596106af3aSPeter Maydell }; 29606106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 29616106af3aSPeter Maydell gen_helper_neon_paddl_u16, 29626106af3aSPeter Maydell gen_helper_neon_paddl_u32, 29636106af3aSPeter Maydell tcg_gen_add_i64, 29646106af3aSPeter Maydell NULL, 29656106af3aSPeter Maydell }; 29666106af3aSPeter Maydell 29676106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 29686106af3aSPeter Maydell } 29696106af3aSPeter Maydell 29706106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 29716106af3aSPeter Maydell { 29726106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 29736106af3aSPeter Maydell gen_helper_neon_widen_s8, 29746106af3aSPeter Maydell gen_helper_neon_widen_s16, 29756106af3aSPeter Maydell tcg_gen_ext_i32_i64, 29766106af3aSPeter Maydell NULL, 29776106af3aSPeter Maydell }; 29786106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 29796106af3aSPeter Maydell gen_helper_neon_paddl_u16, 29806106af3aSPeter Maydell gen_helper_neon_paddl_u32, 29816106af3aSPeter Maydell tcg_gen_add_i64, 29826106af3aSPeter Maydell NULL, 29836106af3aSPeter Maydell }; 29846106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 29856106af3aSPeter Maydell gen_helper_neon_addl_u16, 29866106af3aSPeter Maydell gen_helper_neon_addl_u32, 29876106af3aSPeter Maydell tcg_gen_add_i64, 29886106af3aSPeter Maydell NULL, 29896106af3aSPeter Maydell }; 29906106af3aSPeter Maydell 29916106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 29926106af3aSPeter Maydell accfn[a->size]); 29936106af3aSPeter Maydell } 29946106af3aSPeter Maydell 29956106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 29966106af3aSPeter Maydell { 29976106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 29986106af3aSPeter Maydell gen_helper_neon_widen_u8, 29996106af3aSPeter Maydell gen_helper_neon_widen_u16, 30006106af3aSPeter Maydell tcg_gen_extu_i32_i64, 30016106af3aSPeter Maydell NULL, 30026106af3aSPeter Maydell }; 30036106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30046106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30056106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30066106af3aSPeter Maydell tcg_gen_add_i64, 30076106af3aSPeter Maydell NULL, 30086106af3aSPeter Maydell }; 30096106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 30106106af3aSPeter Maydell gen_helper_neon_addl_u16, 30116106af3aSPeter Maydell gen_helper_neon_addl_u32, 30126106af3aSPeter Maydell tcg_gen_add_i64, 30136106af3aSPeter Maydell NULL, 30146106af3aSPeter Maydell }; 30156106af3aSPeter Maydell 30166106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 30176106af3aSPeter Maydell accfn[a->size]); 30186106af3aSPeter Maydell } 3019567663a2SPeter Maydell 3020567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3021567663a2SPeter Maydell 3022567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3023567663a2SPeter Maydell ZipFn *fn) 3024567663a2SPeter Maydell { 3025567663a2SPeter Maydell TCGv_ptr pd, pm; 3026567663a2SPeter Maydell 3027567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3028567663a2SPeter Maydell return false; 3029567663a2SPeter Maydell } 3030567663a2SPeter Maydell 3031567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3032567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3033567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3034567663a2SPeter Maydell return false; 3035567663a2SPeter Maydell } 3036567663a2SPeter Maydell 3037567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3038567663a2SPeter Maydell return false; 3039567663a2SPeter Maydell } 3040567663a2SPeter Maydell 3041567663a2SPeter Maydell if (!fn) { 3042567663a2SPeter Maydell /* Bad size or size/q combination */ 3043567663a2SPeter Maydell return false; 3044567663a2SPeter Maydell } 3045567663a2SPeter Maydell 3046567663a2SPeter Maydell if (!vfp_access_check(s)) { 3047567663a2SPeter Maydell return true; 3048567663a2SPeter Maydell } 3049567663a2SPeter Maydell 3050567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3051567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3052567663a2SPeter Maydell fn(pd, pm); 3053567663a2SPeter Maydell return true; 3054567663a2SPeter Maydell } 3055567663a2SPeter Maydell 3056567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3057567663a2SPeter Maydell { 3058567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3059567663a2SPeter Maydell { 3060567663a2SPeter Maydell gen_helper_neon_unzip8, 3061567663a2SPeter Maydell gen_helper_neon_unzip16, 3062567663a2SPeter Maydell NULL, 3063567663a2SPeter Maydell NULL, 3064567663a2SPeter Maydell }, { 3065567663a2SPeter Maydell gen_helper_neon_qunzip8, 3066567663a2SPeter Maydell gen_helper_neon_qunzip16, 3067567663a2SPeter Maydell gen_helper_neon_qunzip32, 3068567663a2SPeter Maydell NULL, 3069567663a2SPeter Maydell } 3070567663a2SPeter Maydell }; 3071567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3072567663a2SPeter Maydell } 3073567663a2SPeter Maydell 3074567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3075567663a2SPeter Maydell { 3076567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3077567663a2SPeter Maydell { 3078567663a2SPeter Maydell gen_helper_neon_zip8, 3079567663a2SPeter Maydell gen_helper_neon_zip16, 3080567663a2SPeter Maydell NULL, 3081567663a2SPeter Maydell NULL, 3082567663a2SPeter Maydell }, { 3083567663a2SPeter Maydell gen_helper_neon_qzip8, 3084567663a2SPeter Maydell gen_helper_neon_qzip16, 3085567663a2SPeter Maydell gen_helper_neon_qzip32, 3086567663a2SPeter Maydell NULL, 3087567663a2SPeter Maydell } 3088567663a2SPeter Maydell }; 3089567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3090567663a2SPeter Maydell } 30913882bdacSPeter Maydell 30923882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 30933882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 30943882bdacSPeter Maydell { 30953882bdacSPeter Maydell TCGv_i64 rm; 30963882bdacSPeter Maydell TCGv_i32 rd0, rd1; 30973882bdacSPeter Maydell 30983882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30993882bdacSPeter Maydell return false; 31003882bdacSPeter Maydell } 31013882bdacSPeter Maydell 31023882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 31033882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 31043882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 31053882bdacSPeter Maydell return false; 31063882bdacSPeter Maydell } 31073882bdacSPeter Maydell 31083882bdacSPeter Maydell if (a->vm & 1) { 31093882bdacSPeter Maydell return false; 31103882bdacSPeter Maydell } 31113882bdacSPeter Maydell 31123882bdacSPeter Maydell if (!narrowfn) { 31133882bdacSPeter Maydell return false; 31143882bdacSPeter Maydell } 31153882bdacSPeter Maydell 31163882bdacSPeter Maydell if (!vfp_access_check(s)) { 31173882bdacSPeter Maydell return true; 31183882bdacSPeter Maydell } 31193882bdacSPeter Maydell 31203882bdacSPeter Maydell rm = tcg_temp_new_i64(); 31213882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 31223882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 31233882bdacSPeter Maydell 31240aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 0, MO_64); 3125ad75a51eSRichard Henderson narrowfn(rd0, tcg_env, rm); 31260aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 1, MO_64); 3127ad75a51eSRichard Henderson narrowfn(rd1, tcg_env, rm); 3128a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 3129a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 31303882bdacSPeter Maydell return true; 31313882bdacSPeter Maydell } 31323882bdacSPeter Maydell 31333882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 31343882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 31353882bdacSPeter Maydell { \ 31363882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 31373882bdacSPeter Maydell FUNC##8, \ 31383882bdacSPeter Maydell FUNC##16, \ 31393882bdacSPeter Maydell FUNC##32, \ 31403882bdacSPeter Maydell NULL, \ 31413882bdacSPeter Maydell }; \ 31423882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 31433882bdacSPeter Maydell } 31443882bdacSPeter Maydell 31453882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 31463882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 31473882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 31483882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3149749e2be3SPeter Maydell 3150749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3151749e2be3SPeter Maydell { 3152749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3153749e2be3SPeter Maydell TCGv_i64 rd; 3154749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3155749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3156749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3157749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3158749e2be3SPeter Maydell NULL, 3159749e2be3SPeter Maydell }; 3160749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3161749e2be3SPeter Maydell 3162749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3163749e2be3SPeter Maydell return false; 3164749e2be3SPeter Maydell } 3165749e2be3SPeter Maydell 3166749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3167749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3168749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3169749e2be3SPeter Maydell return false; 3170749e2be3SPeter Maydell } 3171749e2be3SPeter Maydell 3172749e2be3SPeter Maydell if (a->vd & 1) { 3173749e2be3SPeter Maydell return false; 3174749e2be3SPeter Maydell } 3175749e2be3SPeter Maydell 3176749e2be3SPeter Maydell if (!widenfn) { 3177749e2be3SPeter Maydell return false; 3178749e2be3SPeter Maydell } 3179749e2be3SPeter Maydell 3180749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3181749e2be3SPeter Maydell return true; 3182749e2be3SPeter Maydell } 3183749e2be3SPeter Maydell 3184749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3185a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 3186a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 3187749e2be3SPeter Maydell 3188a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 3189a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 3190749e2be3SPeter Maydell 3191749e2be3SPeter Maydell widenfn(rd, rm0); 3192749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 31930aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 0, MO_64); 3194749e2be3SPeter Maydell widenfn(rd, rm1); 3195749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 31960aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 1, MO_64); 3197749e2be3SPeter Maydell return true; 3198749e2be3SPeter Maydell } 3199654a5173SPeter Maydell 3200d29b17caSRichard Henderson static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a) 3201d29b17caSRichard Henderson { 3202d29b17caSRichard Henderson TCGv_ptr fpst; 3203d29b17caSRichard Henderson TCGv_i64 tmp; 3204d29b17caSRichard Henderson TCGv_i32 dst0, dst1; 3205d29b17caSRichard Henderson 3206d29b17caSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 3207d29b17caSRichard Henderson return false; 3208d29b17caSRichard Henderson } 3209d29b17caSRichard Henderson 3210d29b17caSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 3211d29b17caSRichard Henderson if (!dc_isar_feature(aa32_simd_r32, s) && 3212d29b17caSRichard Henderson ((a->vd | a->vm) & 0x10)) { 3213d29b17caSRichard Henderson return false; 3214d29b17caSRichard Henderson } 3215d29b17caSRichard Henderson 3216d29b17caSRichard Henderson if ((a->vm & 1) || (a->size != 1)) { 3217d29b17caSRichard Henderson return false; 3218d29b17caSRichard Henderson } 3219d29b17caSRichard Henderson 3220d29b17caSRichard Henderson if (!vfp_access_check(s)) { 3221d29b17caSRichard Henderson return true; 3222d29b17caSRichard Henderson } 3223d29b17caSRichard Henderson 3224d29b17caSRichard Henderson fpst = fpstatus_ptr(FPST_STD); 3225d29b17caSRichard Henderson tmp = tcg_temp_new_i64(); 3226d29b17caSRichard Henderson dst0 = tcg_temp_new_i32(); 3227d29b17caSRichard Henderson dst1 = tcg_temp_new_i32(); 3228d29b17caSRichard Henderson 3229d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 0, MO_64); 3230d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst0, tmp, fpst); 3231d29b17caSRichard Henderson 3232d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 1, MO_64); 3233d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst1, tmp, fpst); 3234d29b17caSRichard Henderson 3235d29b17caSRichard Henderson write_neon_element32(dst0, a->vd, 0, MO_32); 3236d29b17caSRichard Henderson write_neon_element32(dst1, a->vd, 1, MO_32); 3237d29b17caSRichard Henderson return true; 3238d29b17caSRichard Henderson } 3239d29b17caSRichard Henderson 3240654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3241654a5173SPeter Maydell { 3242654a5173SPeter Maydell TCGv_ptr fpst; 3243654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3244654a5173SPeter Maydell 3245654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3246654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3247654a5173SPeter Maydell return false; 3248654a5173SPeter Maydell } 3249654a5173SPeter Maydell 3250654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3251654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3252654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3253654a5173SPeter Maydell return false; 3254654a5173SPeter Maydell } 3255654a5173SPeter Maydell 3256654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3257654a5173SPeter Maydell return false; 3258654a5173SPeter Maydell } 3259654a5173SPeter Maydell 3260654a5173SPeter Maydell if (!vfp_access_check(s)) { 3261654a5173SPeter Maydell return true; 3262654a5173SPeter Maydell } 3263654a5173SPeter Maydell 3264a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3265654a5173SPeter Maydell ahp = get_ahp_flag(); 3266a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3267a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3268654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3269a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3270a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3271654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3272654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3273654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3274a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 2, MO_32); 3275654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3276a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 3277a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 3, MO_32); 3278a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 0, MO_32); 3279654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3280654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3281654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3282a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 3283654a5173SPeter Maydell return true; 3284654a5173SPeter Maydell } 3285654a5173SPeter Maydell 3286654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3287654a5173SPeter Maydell { 3288654a5173SPeter Maydell TCGv_ptr fpst; 3289654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3290654a5173SPeter Maydell 3291654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3292654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3293654a5173SPeter Maydell return false; 3294654a5173SPeter Maydell } 3295654a5173SPeter Maydell 3296654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3297654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3298654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3299654a5173SPeter Maydell return false; 3300654a5173SPeter Maydell } 3301654a5173SPeter Maydell 3302654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3303654a5173SPeter Maydell return false; 3304654a5173SPeter Maydell } 3305654a5173SPeter Maydell 3306654a5173SPeter Maydell if (!vfp_access_check(s)) { 3307654a5173SPeter Maydell return true; 3308654a5173SPeter Maydell } 3309654a5173SPeter Maydell 3310a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3311654a5173SPeter Maydell ahp = get_ahp_flag(); 3312654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3313a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3314a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3315a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3316a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3317654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3318654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3319a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 0, MO_32); 3320654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3321654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3322a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 1, MO_32); 3323654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3324654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3325a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 2, MO_32); 3326654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3327654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3328a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 3, MO_32); 3329654a5173SPeter Maydell return true; 3330654a5173SPeter Maydell } 333175153179SPeter Maydell 333275153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 333375153179SPeter Maydell { 333475153179SPeter Maydell int vec_size = a->q ? 16 : 8; 3335015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 3336015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 333775153179SPeter Maydell 333875153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 333975153179SPeter Maydell return false; 334075153179SPeter Maydell } 334175153179SPeter Maydell 334275153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 334375153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 334475153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 334575153179SPeter Maydell return false; 334675153179SPeter Maydell } 334775153179SPeter Maydell 334875153179SPeter Maydell if (a->size == 3) { 334975153179SPeter Maydell return false; 335075153179SPeter Maydell } 335175153179SPeter Maydell 335275153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 335375153179SPeter Maydell return false; 335475153179SPeter Maydell } 335575153179SPeter Maydell 335675153179SPeter Maydell if (!vfp_access_check(s)) { 335775153179SPeter Maydell return true; 335875153179SPeter Maydell } 335975153179SPeter Maydell 336075153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 336175153179SPeter Maydell 336275153179SPeter Maydell return true; 336375153179SPeter Maydell } 336475153179SPeter Maydell 336575153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 336675153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 336775153179SPeter Maydell { \ 336875153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 336975153179SPeter Maydell } 337075153179SPeter Maydell 337175153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 337275153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 337375153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 337475153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 337575153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 337675153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 337775153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 337875153179SPeter Maydell 337975153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 338075153179SPeter Maydell { 338175153179SPeter Maydell if (a->size != 0) { 338275153179SPeter Maydell return false; 338375153179SPeter Maydell } 338475153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 338575153179SPeter Maydell } 33860b30dd5bSPeter Maydell 33870b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 33880b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 33890b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 33900b30dd5bSPeter Maydell uint32_t maxsz) \ 33910b30dd5bSPeter Maydell { \ 33920b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 33930b30dd5bSPeter Maydell DATA, FUNC); \ 33940b30dd5bSPeter Maydell } 33950b30dd5bSPeter Maydell 33960b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 33970b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 33980b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 33990b30dd5bSPeter Maydell uint32_t maxsz) \ 34000b30dd5bSPeter Maydell { \ 34010b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 34020b30dd5bSPeter Maydell } 34030b30dd5bSPeter Maydell 34040b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 34050f23908cSRichard Henderson WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aesd, 0) 34060b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 34070f23908cSRichard Henderson WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesimc, 0) 34080b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 34090b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 34100b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 34110b30dd5bSPeter Maydell 34120b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 34130b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 34140b30dd5bSPeter Maydell { \ 34150b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 34160b30dd5bSPeter Maydell return false; \ 34170b30dd5bSPeter Maydell } \ 34180b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 34190b30dd5bSPeter Maydell } 34200b30dd5bSPeter Maydell 34210b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 34220b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 34230b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 34240b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 34250b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 34260b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 34270b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 342889668082SPeter Maydell 342989668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 343089668082SPeter Maydell { 3431a712266fSRichard Henderson TCGv_i32 tmp; 343289668082SPeter Maydell int pass; 343389668082SPeter Maydell 343489668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 343589668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 343689668082SPeter Maydell return false; 343789668082SPeter Maydell } 343889668082SPeter Maydell 343989668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 344089668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 344189668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 344289668082SPeter Maydell return false; 344389668082SPeter Maydell } 344489668082SPeter Maydell 344589668082SPeter Maydell if (!fn) { 344689668082SPeter Maydell return false; 344789668082SPeter Maydell } 344889668082SPeter Maydell 344989668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 345089668082SPeter Maydell return false; 345189668082SPeter Maydell } 345289668082SPeter Maydell 345389668082SPeter Maydell if (!vfp_access_check(s)) { 345489668082SPeter Maydell return true; 345589668082SPeter Maydell } 345689668082SPeter Maydell 3457a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 345889668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3459a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 346089668082SPeter Maydell fn(tmp, tmp); 3461a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 346289668082SPeter Maydell } 346389668082SPeter Maydell return true; 346489668082SPeter Maydell } 346589668082SPeter Maydell 346689668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 346789668082SPeter Maydell { 346889668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 346989668082SPeter Maydell tcg_gen_bswap32_i32, 347089668082SPeter Maydell gen_swap_half, 347189668082SPeter Maydell NULL, 347289668082SPeter Maydell NULL, 347389668082SPeter Maydell }; 347489668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 347589668082SPeter Maydell } 347689668082SPeter Maydell 347789668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 347889668082SPeter Maydell { 347989668082SPeter Maydell if (a->size != 0) { 348089668082SPeter Maydell return false; 348189668082SPeter Maydell } 348289668082SPeter Maydell return do_2misc(s, a, gen_rev16); 348389668082SPeter Maydell } 348484eae770SPeter Maydell 348584eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 348684eae770SPeter Maydell { 348784eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 348884eae770SPeter Maydell gen_helper_neon_cls_s8, 348984eae770SPeter Maydell gen_helper_neon_cls_s16, 349084eae770SPeter Maydell gen_helper_neon_cls_s32, 349184eae770SPeter Maydell NULL, 349284eae770SPeter Maydell }; 349384eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 349484eae770SPeter Maydell } 349584eae770SPeter Maydell 349684eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 349784eae770SPeter Maydell { 349884eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 349984eae770SPeter Maydell } 350084eae770SPeter Maydell 350184eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 350284eae770SPeter Maydell { 350384eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 350484eae770SPeter Maydell gen_helper_neon_clz_u8, 350584eae770SPeter Maydell gen_helper_neon_clz_u16, 350684eae770SPeter Maydell do_VCLZ_32, 350784eae770SPeter Maydell NULL, 350884eae770SPeter Maydell }; 350984eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 351084eae770SPeter Maydell } 351184eae770SPeter Maydell 351284eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 351384eae770SPeter Maydell { 351484eae770SPeter Maydell if (a->size != 0) { 351584eae770SPeter Maydell return false; 351684eae770SPeter Maydell } 351784eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 351884eae770SPeter Maydell } 351984eae770SPeter Maydell 35202b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 35212b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 35222b70d8cdSPeter Maydell { 35232b70d8cdSPeter Maydell tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs, 35242b70d8cdSPeter Maydell vece == MO_16 ? 0x7fff : 0x7fffffff, 35252b70d8cdSPeter Maydell oprsz, maxsz); 35262b70d8cdSPeter Maydell } 35272b70d8cdSPeter Maydell 352884eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 352984eae770SPeter Maydell { 35302b70d8cdSPeter Maydell if (a->size == MO_16) { 35312b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 353284eae770SPeter Maydell return false; 353384eae770SPeter Maydell } 35342b70d8cdSPeter Maydell } else if (a->size != MO_32) { 35352b70d8cdSPeter Maydell return false; 35362b70d8cdSPeter Maydell } 35372b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VABS_F); 35382b70d8cdSPeter Maydell } 35392b70d8cdSPeter Maydell 35402b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 35412b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 35422b70d8cdSPeter Maydell { 35432b70d8cdSPeter Maydell tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs, 35442b70d8cdSPeter Maydell vece == MO_16 ? 0x8000 : 0x80000000, 35452b70d8cdSPeter Maydell oprsz, maxsz); 354684eae770SPeter Maydell } 354784eae770SPeter Maydell 354884eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 354984eae770SPeter Maydell { 35502b70d8cdSPeter Maydell if (a->size == MO_16) { 35512b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 355284eae770SPeter Maydell return false; 355384eae770SPeter Maydell } 35542b70d8cdSPeter Maydell } else if (a->size != MO_32) { 35552b70d8cdSPeter Maydell return false; 35562b70d8cdSPeter Maydell } 35572b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VNEG_F); 355884eae770SPeter Maydell } 355984eae770SPeter Maydell 356084eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 356184eae770SPeter Maydell { 356284eae770SPeter Maydell if (a->size != 2) { 356384eae770SPeter Maydell return false; 356484eae770SPeter Maydell } 356584eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 356684eae770SPeter Maydell } 356784eae770SPeter Maydell 356884eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 356984eae770SPeter Maydell { 357084eae770SPeter Maydell if (a->size != 2) { 357184eae770SPeter Maydell return false; 357284eae770SPeter Maydell } 357384eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 357484eae770SPeter Maydell } 35754936f38aSPeter Maydell 35764936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 35774936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 35784936f38aSPeter Maydell { \ 3579ad75a51eSRichard Henderson FUNC(d, tcg_env, m); \ 35804936f38aSPeter Maydell } 35814936f38aSPeter Maydell 35824936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 35834936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 35844936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 35854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 35864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 35874936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 35884936f38aSPeter Maydell 35894936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 35904936f38aSPeter Maydell { 35914936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 35924936f38aSPeter Maydell gen_VQABS_s8, 35934936f38aSPeter Maydell gen_VQABS_s16, 35944936f38aSPeter Maydell gen_VQABS_s32, 35954936f38aSPeter Maydell NULL, 35964936f38aSPeter Maydell }; 35974936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 35984936f38aSPeter Maydell } 35994936f38aSPeter Maydell 36004936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 36014936f38aSPeter Maydell { 36024936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 36034936f38aSPeter Maydell gen_VQNEG_s8, 36044936f38aSPeter Maydell gen_VQNEG_s16, 36054936f38aSPeter Maydell gen_VQNEG_s32, 36064936f38aSPeter Maydell NULL, 36074936f38aSPeter Maydell }; 36084936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 36094936f38aSPeter Maydell } 36103e96b205SPeter Maydell 36114a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC) \ 36124a15d9a3SPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 36134a15d9a3SPeter Maydell uint32_t rm_ofs, \ 36144a15d9a3SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 36154a15d9a3SPeter Maydell { \ 36164a15d9a3SPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 36174a15d9a3SPeter Maydell NULL, HFUNC, SFUNC, NULL, \ 36184a15d9a3SPeter Maydell }; \ 36194a15d9a3SPeter Maydell TCGv_ptr fpst; \ 36204a15d9a3SPeter Maydell fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD); \ 36214a15d9a3SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0, \ 36224a15d9a3SPeter Maydell fns[vece]); \ 36234a15d9a3SPeter Maydell } \ 36244a15d9a3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 36254a15d9a3SPeter Maydell { \ 36264a15d9a3SPeter Maydell if (a->size == MO_16) { \ 36274a15d9a3SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 36284a15d9a3SPeter Maydell return false; \ 36294a15d9a3SPeter Maydell } \ 36304a15d9a3SPeter Maydell } else if (a->size != MO_32) { \ 36314a15d9a3SPeter Maydell return false; \ 36324a15d9a3SPeter Maydell } \ 36334a15d9a3SPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 36344a15d9a3SPeter Maydell } 36354a15d9a3SPeter Maydell 36364a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s) 36374a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s) 3638635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s) 3639635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s) 3640635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s) 3641635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s) 3642635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s) 36437782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos) 36447782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos) 36457782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs) 36467782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs) 36474a15d9a3SPeter Maydell 364823afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s) 364923afcdd2SPeter Maydell 36503e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 36513e96b205SPeter Maydell { 36523e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 36533e96b205SPeter Maydell return false; 36543e96b205SPeter Maydell } 365523afcdd2SPeter Maydell return trans_VRINTX_impl(s, a); 36563e96b205SPeter Maydell } 3657baa59323SPeter Maydell 3658ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP) \ 3659ca88a6efSPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 3660ca88a6efSPeter Maydell uint32_t rm_ofs, \ 3661ca88a6efSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 3662ca88a6efSPeter Maydell { \ 3663ca88a6efSPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 3664ca88a6efSPeter Maydell NULL, \ 3665ca88a6efSPeter Maydell gen_helper_gvec_##OP##h, \ 3666ca88a6efSPeter Maydell gen_helper_gvec_##OP##s, \ 3667ca88a6efSPeter Maydell NULL, \ 3668ca88a6efSPeter Maydell }; \ 3669ca88a6efSPeter Maydell TCGv_ptr fpst; \ 3670ca88a6efSPeter Maydell fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD); \ 3671ca88a6efSPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, \ 3672ca88a6efSPeter Maydell arm_rmode_to_sf(RMODE), fns[vece]); \ 3673ca88a6efSPeter Maydell } \ 3674a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3675a183d5fbSPeter Maydell { \ 3676ca88a6efSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { \ 3677ca88a6efSPeter Maydell return false; \ 3678ca88a6efSPeter Maydell } \ 3679ca88a6efSPeter Maydell if (a->size == MO_16) { \ 3680ca88a6efSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 3681ca88a6efSPeter Maydell return false; \ 3682ca88a6efSPeter Maydell } \ 3683ca88a6efSPeter Maydell } else if (a->size != MO_32) { \ 3684ca88a6efSPeter Maydell return false; \ 3685ca88a6efSPeter Maydell } \ 3686ca88a6efSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 3687a183d5fbSPeter Maydell } 3688a183d5fbSPeter Maydell 3689ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u) 3690ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s) 3691ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u) 3692ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s) 3693ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u) 3694ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s) 3695ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u) 3696ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s) 36978ab3a227SPeter Maydell 369818725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_) 369918725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_) 370018725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_) 370118725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_) 370218725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_) 370318725916SPeter Maydell 37048ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 37058ab3a227SPeter Maydell { 37068ab3a227SPeter Maydell TCGv_i64 rm, rd; 37078ab3a227SPeter Maydell int pass; 37088ab3a227SPeter Maydell 37098ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 37108ab3a227SPeter Maydell return false; 37118ab3a227SPeter Maydell } 37128ab3a227SPeter Maydell 37138ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 37148ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 37158ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 37168ab3a227SPeter Maydell return false; 37178ab3a227SPeter Maydell } 37188ab3a227SPeter Maydell 37198ab3a227SPeter Maydell if (a->size != 0) { 37208ab3a227SPeter Maydell return false; 37218ab3a227SPeter Maydell } 37228ab3a227SPeter Maydell 37238ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 37248ab3a227SPeter Maydell return false; 37258ab3a227SPeter Maydell } 37268ab3a227SPeter Maydell 37278ab3a227SPeter Maydell if (!vfp_access_check(s)) { 37288ab3a227SPeter Maydell return true; 37298ab3a227SPeter Maydell } 37308ab3a227SPeter Maydell 37318ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 37328ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 37338ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 37340aa8e700SRichard Henderson read_neon_element64(rm, a->vm, pass, MO_64); 37350aa8e700SRichard Henderson read_neon_element64(rd, a->vd, pass, MO_64); 37360aa8e700SRichard Henderson write_neon_element64(rm, a->vd, pass, MO_64); 37370aa8e700SRichard Henderson write_neon_element64(rd, a->vm, pass, MO_64); 37388ab3a227SPeter Maydell } 37398ab3a227SPeter Maydell return true; 37408ab3a227SPeter Maydell } 374124f4531dSRichard Henderson 3742d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 3743d4366190SPeter Maydell { 3744d4366190SPeter Maydell TCGv_i32 rd, tmp; 3745d4366190SPeter Maydell 3746d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3747d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3748d4366190SPeter Maydell 3749d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 3750d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 3751d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 3752d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3753d4366190SPeter Maydell 3754d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 3755d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 3756d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 3757d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3758d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3759d4366190SPeter Maydell } 3760d4366190SPeter Maydell 3761d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 3762d4366190SPeter Maydell { 3763d4366190SPeter Maydell TCGv_i32 rd, tmp; 3764d4366190SPeter Maydell 3765d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3766d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3767d4366190SPeter Maydell 3768d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 3769d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 3770d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3771d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 3772d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 3773d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3774d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3775d4366190SPeter Maydell } 3776d4366190SPeter Maydell 3777d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 3778d4366190SPeter Maydell { 3779d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 3780d4366190SPeter Maydell int pass; 3781d4366190SPeter Maydell 3782d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3783d4366190SPeter Maydell return false; 3784d4366190SPeter Maydell } 3785d4366190SPeter Maydell 3786d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3787d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3788d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3789d4366190SPeter Maydell return false; 3790d4366190SPeter Maydell } 3791d4366190SPeter Maydell 3792d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 3793d4366190SPeter Maydell return false; 3794d4366190SPeter Maydell } 3795d4366190SPeter Maydell 3796d4366190SPeter Maydell if (a->size == 3) { 3797d4366190SPeter Maydell return false; 3798d4366190SPeter Maydell } 3799d4366190SPeter Maydell 3800d4366190SPeter Maydell if (!vfp_access_check(s)) { 3801d4366190SPeter Maydell return true; 3802d4366190SPeter Maydell } 3803d4366190SPeter Maydell 3804a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3805a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3806a712266fSRichard Henderson if (a->size == MO_32) { 3807d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 3808a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3809a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass + 1, MO_32); 3810a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3811a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass + 1, MO_32); 3812d4366190SPeter Maydell } 3813d4366190SPeter Maydell } else { 3814d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3815a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3816a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass, MO_32); 3817a712266fSRichard Henderson if (a->size == MO_8) { 3818d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 3819d4366190SPeter Maydell } else { 3820d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 3821d4366190SPeter Maydell } 3822a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3823a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 3824d4366190SPeter Maydell } 3825d4366190SPeter Maydell } 3826d4366190SPeter Maydell return true; 3827d4366190SPeter Maydell } 38282323c5ffSRichard Henderson 38292323c5ffSRichard Henderson static bool trans_VSMMLA(DisasContext *s, arg_VSMMLA *a) 38302323c5ffSRichard Henderson { 38312323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 38322323c5ffSRichard Henderson return false; 38332323c5ffSRichard Henderson } 38342323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 38352323c5ffSRichard Henderson gen_helper_gvec_smmla_b); 38362323c5ffSRichard Henderson } 38372323c5ffSRichard Henderson 38382323c5ffSRichard Henderson static bool trans_VUMMLA(DisasContext *s, arg_VUMMLA *a) 38392323c5ffSRichard Henderson { 38402323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 38412323c5ffSRichard Henderson return false; 38422323c5ffSRichard Henderson } 38432323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 38442323c5ffSRichard Henderson gen_helper_gvec_ummla_b); 38452323c5ffSRichard Henderson } 38462323c5ffSRichard Henderson 38472323c5ffSRichard Henderson static bool trans_VUSMMLA(DisasContext *s, arg_VUSMMLA *a) 38482323c5ffSRichard Henderson { 38492323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 38502323c5ffSRichard Henderson return false; 38512323c5ffSRichard Henderson } 38522323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 38532323c5ffSRichard Henderson gen_helper_gvec_usmmla_b); 38542323c5ffSRichard Henderson } 385581266a1fSRichard Henderson 385681266a1fSRichard Henderson static bool trans_VMMLA_b16(DisasContext *s, arg_VMMLA_b16 *a) 385781266a1fSRichard Henderson { 385881266a1fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 385981266a1fSRichard Henderson return false; 386081266a1fSRichard Henderson } 386181266a1fSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 386281266a1fSRichard Henderson gen_helper_gvec_bfmmla); 386381266a1fSRichard Henderson } 38645693887fSRichard Henderson 38655693887fSRichard Henderson static bool trans_VFMA_b16(DisasContext *s, arg_VFMA_b16 *a) 38665693887fSRichard Henderson { 38675693887fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 38685693887fSRichard Henderson return false; 38695693887fSRichard Henderson } 38705693887fSRichard Henderson return do_neon_ddda_fpst(s, 7, a->vd, a->vn, a->vm, a->q, FPST_STD, 38715693887fSRichard Henderson gen_helper_gvec_bfmlal); 38725693887fSRichard Henderson } 3873458d0ab6SRichard Henderson 3874458d0ab6SRichard Henderson static bool trans_VFMA_b16_scal(DisasContext *s, arg_VFMA_b16_scal *a) 3875458d0ab6SRichard Henderson { 3876458d0ab6SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 3877458d0ab6SRichard Henderson return false; 3878458d0ab6SRichard Henderson } 3879458d0ab6SRichard Henderson return do_neon_ddda_fpst(s, 6, a->vd, a->vn, a->vm, 3880458d0ab6SRichard Henderson (a->index << 1) | a->q, FPST_STD, 3881458d0ab6SRichard Henderson gen_helper_gvec_bfmlal_idx); 3882458d0ab6SRichard Henderson } 3883