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 "tcg/tcg-op.h" 254800b852SPeter Maydell #include "tcg/tcg-op-gvec.h" 264800b852SPeter Maydell #include "exec/exec-all.h" 274800b852SPeter Maydell #include "exec/gen-icount.h" 284800b852SPeter Maydell #include "translate.h" 294800b852SPeter Maydell #include "translate-a32.h" 30625e3dd4SPeter Maydell 31625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 32139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc" 33139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc" 34139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc" 35afff8de0SPeter Maydell 36eb554d61SPeter Maydell static TCGv_ptr vfp_reg_ptr(bool dp, int reg) 37eb554d61SPeter Maydell { 38eb554d61SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 39eb554d61SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); 40eb554d61SPeter Maydell return ret; 41eb554d61SPeter Maydell } 42eb554d61SPeter Maydell 436fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) 446fb57878SPeter Maydell { 456fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 466fb57878SPeter Maydell 476fb57878SPeter Maydell switch (mop) { 486fb57878SPeter Maydell case MO_UB: 496fb57878SPeter Maydell tcg_gen_ld8u_i32(var, cpu_env, offset); 506fb57878SPeter Maydell break; 516fb57878SPeter Maydell case MO_UW: 526fb57878SPeter Maydell tcg_gen_ld16u_i32(var, cpu_env, offset); 536fb57878SPeter Maydell break; 546fb57878SPeter Maydell case MO_UL: 556fb57878SPeter Maydell tcg_gen_ld_i32(var, cpu_env, offset); 566fb57878SPeter Maydell break; 576fb57878SPeter Maydell default: 586fb57878SPeter Maydell g_assert_not_reached(); 596fb57878SPeter Maydell } 606fb57878SPeter Maydell } 616fb57878SPeter Maydell 626fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) 636fb57878SPeter Maydell { 646fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 656fb57878SPeter Maydell 666fb57878SPeter Maydell switch (mop) { 676fb57878SPeter Maydell case MO_UB: 686fb57878SPeter Maydell tcg_gen_ld8u_i64(var, cpu_env, offset); 696fb57878SPeter Maydell break; 706fb57878SPeter Maydell case MO_UW: 716fb57878SPeter Maydell tcg_gen_ld16u_i64(var, cpu_env, offset); 726fb57878SPeter Maydell break; 736fb57878SPeter Maydell case MO_UL: 746fb57878SPeter Maydell tcg_gen_ld32u_i64(var, cpu_env, offset); 756fb57878SPeter Maydell break; 76fc313c64SFrédéric Pétrot case MO_UQ: 776fb57878SPeter Maydell tcg_gen_ld_i64(var, cpu_env, offset); 786fb57878SPeter Maydell break; 796fb57878SPeter Maydell default: 806fb57878SPeter Maydell g_assert_not_reached(); 816fb57878SPeter Maydell } 826fb57878SPeter Maydell } 836fb57878SPeter Maydell 846fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) 856fb57878SPeter Maydell { 866fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 876fb57878SPeter Maydell 886fb57878SPeter Maydell switch (size) { 896fb57878SPeter Maydell case MO_8: 906fb57878SPeter Maydell tcg_gen_st8_i32(var, cpu_env, offset); 916fb57878SPeter Maydell break; 926fb57878SPeter Maydell case MO_16: 936fb57878SPeter Maydell tcg_gen_st16_i32(var, cpu_env, offset); 946fb57878SPeter Maydell break; 956fb57878SPeter Maydell case MO_32: 966fb57878SPeter Maydell tcg_gen_st_i32(var, cpu_env, offset); 976fb57878SPeter Maydell break; 986fb57878SPeter Maydell default: 996fb57878SPeter Maydell g_assert_not_reached(); 1006fb57878SPeter Maydell } 1016fb57878SPeter Maydell } 1026fb57878SPeter Maydell 1036fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) 1046fb57878SPeter Maydell { 1056fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1066fb57878SPeter Maydell 1076fb57878SPeter Maydell switch (size) { 1086fb57878SPeter Maydell case MO_8: 1096fb57878SPeter Maydell tcg_gen_st8_i64(var, cpu_env, offset); 1106fb57878SPeter Maydell break; 1116fb57878SPeter Maydell case MO_16: 1126fb57878SPeter Maydell tcg_gen_st16_i64(var, cpu_env, offset); 1136fb57878SPeter Maydell break; 1146fb57878SPeter Maydell case MO_32: 1156fb57878SPeter Maydell tcg_gen_st32_i64(var, cpu_env, offset); 1166fb57878SPeter Maydell break; 1176fb57878SPeter Maydell case MO_64: 1186fb57878SPeter Maydell tcg_gen_st_i64(var, cpu_env, offset); 1196fb57878SPeter Maydell break; 1206fb57878SPeter Maydell default: 1216fb57878SPeter Maydell g_assert_not_reached(); 1226fb57878SPeter Maydell } 1236fb57878SPeter Maydell } 1246fb57878SPeter Maydell 1255a46304cSRichard Henderson static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm, 1265a46304cSRichard Henderson int data, gen_helper_gvec_4 *fn_gvec) 1275a46304cSRichard Henderson { 1285a46304cSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 1295a46304cSRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 1305a46304cSRichard Henderson return false; 1315a46304cSRichard Henderson } 1325a46304cSRichard Henderson 1335a46304cSRichard Henderson /* 1345a46304cSRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 1355a46304cSRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 1365a46304cSRichard Henderson * when we have mixed Q- and D-reg inputs. 1375a46304cSRichard Henderson */ 1385a46304cSRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 1395a46304cSRichard Henderson return false; 1405a46304cSRichard Henderson } 1415a46304cSRichard Henderson 1425a46304cSRichard Henderson if (!vfp_access_check(s)) { 1435a46304cSRichard Henderson return true; 1445a46304cSRichard Henderson } 1455a46304cSRichard Henderson 1465a46304cSRichard Henderson int opr_sz = q ? 16 : 8; 1475a46304cSRichard Henderson tcg_gen_gvec_4_ool(vfp_reg_offset(1, vd), 1485a46304cSRichard Henderson vfp_reg_offset(1, vn), 1495a46304cSRichard Henderson vfp_reg_offset(1, vm), 1505a46304cSRichard Henderson vfp_reg_offset(1, vd), 1515a46304cSRichard Henderson opr_sz, opr_sz, data, fn_gvec); 1525a46304cSRichard Henderson return true; 1535a46304cSRichard Henderson } 1545a46304cSRichard Henderson 155505fce50SRichard Henderson static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, 156505fce50SRichard Henderson int data, ARMFPStatusFlavour fp_flavour, 157505fce50SRichard Henderson gen_helper_gvec_4_ptr *fn_gvec_ptr) 158afff8de0SPeter Maydell { 159afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 160505fce50SRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 161afff8de0SPeter Maydell return false; 162afff8de0SPeter Maydell } 163afff8de0SPeter Maydell 164505fce50SRichard Henderson /* 165505fce50SRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 166505fce50SRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 167505fce50SRichard Henderson * when we have mixed Q- and D-reg inputs. 168505fce50SRichard Henderson */ 169505fce50SRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 170afff8de0SPeter Maydell return false; 171afff8de0SPeter Maydell } 172afff8de0SPeter Maydell 173afff8de0SPeter Maydell if (!vfp_access_check(s)) { 174afff8de0SPeter Maydell return true; 175afff8de0SPeter Maydell } 176afff8de0SPeter Maydell 177505fce50SRichard Henderson int opr_sz = q ? 16 : 8; 178505fce50SRichard Henderson TCGv_ptr fpst = fpstatus_ptr(fp_flavour); 179505fce50SRichard Henderson 180505fce50SRichard Henderson tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd), 181505fce50SRichard Henderson vfp_reg_offset(1, vn), 182505fce50SRichard Henderson vfp_reg_offset(1, vm), 183505fce50SRichard Henderson vfp_reg_offset(1, vd), 184505fce50SRichard Henderson fpst, opr_sz, opr_sz, data, fn_gvec_ptr); 185afff8de0SPeter Maydell return true; 186afff8de0SPeter Maydell } 18794d5eb7bSPeter Maydell 188505fce50SRichard Henderson static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 189505fce50SRichard Henderson { 190505fce50SRichard Henderson if (!dc_isar_feature(aa32_vcma, s)) { 191505fce50SRichard Henderson return false; 192505fce50SRichard Henderson } 193505fce50SRichard Henderson if (a->size == MO_16) { 194505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 195505fce50SRichard Henderson return false; 196505fce50SRichard Henderson } 197505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 198505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah); 199505fce50SRichard Henderson } 200505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 201505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas); 202505fce50SRichard Henderson } 203505fce50SRichard Henderson 20494d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 20594d5eb7bSPeter Maydell { 20694d5eb7bSPeter Maydell int opr_sz; 20794d5eb7bSPeter Maydell TCGv_ptr fpst; 20894d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 20994d5eb7bSPeter Maydell 21094d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 211d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 21294d5eb7bSPeter Maydell return false; 21394d5eb7bSPeter Maydell } 21494d5eb7bSPeter Maydell 21594d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 21694d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 21794d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 21894d5eb7bSPeter Maydell return false; 21994d5eb7bSPeter Maydell } 22094d5eb7bSPeter Maydell 22194d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 22294d5eb7bSPeter Maydell return false; 22394d5eb7bSPeter Maydell } 22494d5eb7bSPeter Maydell 22594d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 22694d5eb7bSPeter Maydell return true; 22794d5eb7bSPeter Maydell } 22894d5eb7bSPeter Maydell 22994d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 230d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 231d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 232d186a485SPeter Maydell gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds; 23394d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 23494d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 23594d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 23694d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 23794d5eb7bSPeter Maydell fn_gvec_ptr); 23894d5eb7bSPeter Maydell return true; 23994d5eb7bSPeter Maydell } 24032da0e33SPeter Maydell 241f0ad96cbSRichard Henderson static bool trans_VSDOT(DisasContext *s, arg_VSDOT *a) 24232da0e33SPeter Maydell { 24332da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 24432da0e33SPeter Maydell return false; 24532da0e33SPeter Maydell } 2465a46304cSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 247f0ad96cbSRichard Henderson gen_helper_gvec_sdot_b); 248f0ad96cbSRichard Henderson } 249f0ad96cbSRichard Henderson 250f0ad96cbSRichard Henderson static bool trans_VUDOT(DisasContext *s, arg_VUDOT *a) 251f0ad96cbSRichard Henderson { 252f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 253f0ad96cbSRichard Henderson return false; 254f0ad96cbSRichard Henderson } 255f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 256f0ad96cbSRichard Henderson gen_helper_gvec_udot_b); 25732da0e33SPeter Maydell } 2589a107e7bSPeter Maydell 25951879c67SRichard Henderson static bool trans_VUSDOT(DisasContext *s, arg_VUSDOT *a) 26051879c67SRichard Henderson { 26151879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 26251879c67SRichard Henderson return false; 26351879c67SRichard Henderson } 26451879c67SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 26551879c67SRichard Henderson gen_helper_gvec_usdot_b); 26651879c67SRichard Henderson } 26751879c67SRichard Henderson 268cb8657f7SRichard Henderson static bool trans_VDOT_b16(DisasContext *s, arg_VDOT_b16 *a) 269cb8657f7SRichard Henderson { 270cb8657f7SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 271cb8657f7SRichard Henderson return false; 272cb8657f7SRichard Henderson } 273cb8657f7SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 274cb8657f7SRichard Henderson gen_helper_gvec_bfdot); 275cb8657f7SRichard Henderson } 276cb8657f7SRichard Henderson 2779a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 2789a107e7bSPeter Maydell { 2799a107e7bSPeter Maydell int opr_sz; 2809a107e7bSPeter Maydell 2819a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 2829a107e7bSPeter Maydell return false; 2839a107e7bSPeter Maydell } 2849a107e7bSPeter Maydell 2859a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2869a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2879a107e7bSPeter Maydell (a->vd & 0x10)) { 2889a107e7bSPeter Maydell return false; 2899a107e7bSPeter Maydell } 2909a107e7bSPeter Maydell 2919a107e7bSPeter Maydell if (a->vd & a->q) { 2929a107e7bSPeter Maydell return false; 2939a107e7bSPeter Maydell } 2949a107e7bSPeter Maydell 2959a107e7bSPeter Maydell if (!vfp_access_check(s)) { 2969a107e7bSPeter Maydell return true; 2979a107e7bSPeter Maydell } 2989a107e7bSPeter Maydell 2999a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 3009a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 3019a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 3029a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 3039a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 3049a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 3059a107e7bSPeter Maydell return true; 3069a107e7bSPeter Maydell } 3077e1b5d61SPeter Maydell 3087e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 3097e1b5d61SPeter Maydell { 310505fce50SRichard Henderson int data = (a->index << 2) | a->rot; 3117e1b5d61SPeter Maydell 3127e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 3137e1b5d61SPeter Maydell return false; 3147e1b5d61SPeter Maydell } 315505fce50SRichard Henderson if (a->size == MO_16) { 316505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 3177e1b5d61SPeter Maydell return false; 3187e1b5d61SPeter Maydell } 319505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 320505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah_idx); 3217e1b5d61SPeter Maydell } 322505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 323505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas_idx); 3247e1b5d61SPeter Maydell } 32535f5d4d1SPeter Maydell 326f0ad96cbSRichard Henderson static bool trans_VSDOT_scalar(DisasContext *s, arg_VSDOT_scalar *a) 32735f5d4d1SPeter Maydell { 32835f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 32935f5d4d1SPeter Maydell return false; 33035f5d4d1SPeter Maydell } 3315a46304cSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 332f0ad96cbSRichard Henderson gen_helper_gvec_sdot_idx_b); 333f0ad96cbSRichard Henderson } 334f0ad96cbSRichard Henderson 335f0ad96cbSRichard Henderson static bool trans_VUDOT_scalar(DisasContext *s, arg_VUDOT_scalar *a) 336f0ad96cbSRichard Henderson { 337f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 338f0ad96cbSRichard Henderson return false; 339f0ad96cbSRichard Henderson } 340f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 341f0ad96cbSRichard Henderson gen_helper_gvec_udot_idx_b); 34235f5d4d1SPeter Maydell } 343d27e82f7SPeter Maydell 34451879c67SRichard Henderson static bool trans_VUSDOT_scalar(DisasContext *s, arg_VUSDOT_scalar *a) 34551879c67SRichard Henderson { 34651879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 34751879c67SRichard Henderson return false; 34851879c67SRichard Henderson } 34951879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 35051879c67SRichard Henderson gen_helper_gvec_usdot_idx_b); 35151879c67SRichard Henderson } 35251879c67SRichard Henderson 35351879c67SRichard Henderson static bool trans_VSUDOT_scalar(DisasContext *s, arg_VSUDOT_scalar *a) 35451879c67SRichard Henderson { 35551879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 35651879c67SRichard Henderson return false; 35751879c67SRichard Henderson } 35851879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 35951879c67SRichard Henderson gen_helper_gvec_sudot_idx_b); 36051879c67SRichard Henderson } 36151879c67SRichard Henderson 36283914478SRichard Henderson static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a) 36383914478SRichard Henderson { 36483914478SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 36583914478SRichard Henderson return false; 36683914478SRichard Henderson } 36783914478SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 36883914478SRichard Henderson gen_helper_gvec_bfdot_idx); 36983914478SRichard Henderson } 37083914478SRichard Henderson 371d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 372d27e82f7SPeter Maydell { 373d27e82f7SPeter Maydell int opr_sz; 374d27e82f7SPeter Maydell 375d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 376d27e82f7SPeter Maydell return false; 377d27e82f7SPeter Maydell } 378d27e82f7SPeter Maydell 379d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 380d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 381d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 382d27e82f7SPeter Maydell return false; 383d27e82f7SPeter Maydell } 384d27e82f7SPeter Maydell 385d27e82f7SPeter Maydell if (a->vd & a->q) { 386d27e82f7SPeter Maydell return false; 387d27e82f7SPeter Maydell } 388d27e82f7SPeter Maydell 389d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 390d27e82f7SPeter Maydell return true; 391d27e82f7SPeter Maydell } 392d27e82f7SPeter Maydell 393d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 394d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 395d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 396d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 397d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 398d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 399d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 400d27e82f7SPeter Maydell return true; 401d27e82f7SPeter Maydell } 402a27b4630SPeter Maydell 403a27b4630SPeter Maydell static struct { 404a27b4630SPeter Maydell int nregs; 405a27b4630SPeter Maydell int interleave; 406a27b4630SPeter Maydell int spacing; 407a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 408a27b4630SPeter Maydell {1, 4, 1}, 409a27b4630SPeter Maydell {1, 4, 2}, 410a27b4630SPeter Maydell {4, 1, 1}, 411a27b4630SPeter Maydell {2, 2, 2}, 412a27b4630SPeter Maydell {1, 3, 1}, 413a27b4630SPeter Maydell {1, 3, 2}, 414a27b4630SPeter Maydell {3, 1, 1}, 415a27b4630SPeter Maydell {1, 1, 1}, 416a27b4630SPeter Maydell {1, 2, 1}, 417a27b4630SPeter Maydell {1, 2, 2}, 418a27b4630SPeter Maydell {2, 1, 1} 419a27b4630SPeter Maydell }; 420a27b4630SPeter Maydell 421a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 422a27b4630SPeter Maydell int stride) 423a27b4630SPeter Maydell { 424a27b4630SPeter Maydell if (rm != 15) { 425a27b4630SPeter Maydell TCGv_i32 base; 426a27b4630SPeter Maydell 427a27b4630SPeter Maydell base = load_reg(s, rn); 428a27b4630SPeter Maydell if (rm == 13) { 429a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 430a27b4630SPeter Maydell } else { 431a27b4630SPeter Maydell TCGv_i32 index; 432a27b4630SPeter Maydell index = load_reg(s, rm); 433a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 434a27b4630SPeter Maydell } 435a27b4630SPeter Maydell store_reg(s, rn, base); 436a27b4630SPeter Maydell } 437a27b4630SPeter Maydell } 438a27b4630SPeter Maydell 439a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 440a27b4630SPeter Maydell { 441a27b4630SPeter Maydell /* Neon load/store multiple structures */ 442a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 4437c68c196SRichard Henderson MemOp mop, align, endian; 444a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 445a27b4630SPeter Maydell int size = a->size; 446a27b4630SPeter Maydell TCGv_i64 tmp64; 447d9b47e97SRichard Henderson TCGv_i32 addr; 448a27b4630SPeter Maydell 449a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 450a27b4630SPeter Maydell return false; 451a27b4630SPeter Maydell } 452a27b4630SPeter Maydell 453a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 454a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 455a27b4630SPeter Maydell return false; 456a27b4630SPeter Maydell } 457a27b4630SPeter Maydell if (a->itype > 10) { 458a27b4630SPeter Maydell return false; 459a27b4630SPeter Maydell } 460a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 461a27b4630SPeter Maydell switch (a->itype & 0xc) { 462a27b4630SPeter Maydell case 4: 463a27b4630SPeter Maydell if (a->align >= 2) { 464a27b4630SPeter Maydell return false; 465a27b4630SPeter Maydell } 466a27b4630SPeter Maydell break; 467a27b4630SPeter Maydell case 8: 468a27b4630SPeter Maydell if (a->align == 3) { 469a27b4630SPeter Maydell return false; 470a27b4630SPeter Maydell } 471a27b4630SPeter Maydell break; 472a27b4630SPeter Maydell default: 473a27b4630SPeter Maydell break; 474a27b4630SPeter Maydell } 475a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 476a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 477a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 478a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 479a27b4630SPeter Maydell return false; 480a27b4630SPeter Maydell } 481a27b4630SPeter Maydell 482a27b4630SPeter Maydell if (!vfp_access_check(s)) { 483a27b4630SPeter Maydell return true; 484a27b4630SPeter Maydell } 485a27b4630SPeter Maydell 486a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 4877c68c196SRichard Henderson endian = s->be_data; 488a27b4630SPeter Maydell if (size == 0) { 489a27b4630SPeter Maydell endian = MO_LE; 490a27b4630SPeter Maydell } 4917c68c196SRichard Henderson 4927c68c196SRichard Henderson /* Enforce alignment requested by the instruction */ 4937c68c196SRichard Henderson if (a->align) { 4947c68c196SRichard Henderson align = pow2_align(a->align + 2); /* 4 ** a->align */ 4957c68c196SRichard Henderson } else { 4967c68c196SRichard Henderson align = s->align_mem ? MO_ALIGN : 0; 4977c68c196SRichard Henderson } 4987c68c196SRichard Henderson 499a27b4630SPeter Maydell /* 500a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 501a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 502a27b4630SPeter Maydell */ 503a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 5047c68c196SRichard Henderson /* Retain any natural alignment. */ 5057c68c196SRichard Henderson if (align == MO_ALIGN) { 5067c68c196SRichard Henderson align = pow2_align(size); 5077c68c196SRichard Henderson } 508a27b4630SPeter Maydell size = 3; 509a27b4630SPeter Maydell } 5107c68c196SRichard Henderson 511a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 512a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 513a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 5147c68c196SRichard Henderson 5157c68c196SRichard Henderson mop = endian | size | align; 516a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 517a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 518a27b4630SPeter Maydell int xs; 519a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 520a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 521a27b4630SPeter Maydell 522a27b4630SPeter Maydell if (a->l) { 5237c68c196SRichard Henderson gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop); 524a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 525a27b4630SPeter Maydell } else { 526a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 5277c68c196SRichard Henderson gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); 528a27b4630SPeter Maydell } 529d9b47e97SRichard Henderson tcg_gen_addi_i32(addr, addr, 1 << size); 5307c68c196SRichard Henderson 5317c68c196SRichard Henderson /* Subsequent memory operations inherit alignment */ 5327c68c196SRichard Henderson mop &= ~MO_AMASK; 533a27b4630SPeter Maydell } 534a27b4630SPeter Maydell } 535a27b4630SPeter Maydell } 536a27b4630SPeter Maydell 537a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 538a27b4630SPeter Maydell return true; 539a27b4630SPeter Maydell } 5403698747cSPeter Maydell 5413698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5423698747cSPeter Maydell { 5433698747cSPeter Maydell /* Neon load single structure to all lanes */ 5443698747cSPeter Maydell int reg, stride, vec_size; 5453698747cSPeter Maydell int vd = a->vd; 5463698747cSPeter Maydell int size = a->size; 5473698747cSPeter Maydell int nregs = a->n + 1; 5483698747cSPeter Maydell TCGv_i32 addr, tmp; 549a8502b37SRichard Henderson MemOp mop, align; 5503698747cSPeter Maydell 5513698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5523698747cSPeter Maydell return false; 5533698747cSPeter Maydell } 5543698747cSPeter Maydell 5553698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5563698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5573698747cSPeter Maydell return false; 5583698747cSPeter Maydell } 5593698747cSPeter Maydell 560a8502b37SRichard Henderson align = 0; 5613698747cSPeter Maydell if (size == 3) { 5623698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5633698747cSPeter Maydell return false; 5643698747cSPeter Maydell } 5653698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 566a8502b37SRichard Henderson size = MO_32; 567a8502b37SRichard Henderson align = MO_ALIGN_16; 568a8502b37SRichard Henderson } else if (a->a) { 569a8502b37SRichard Henderson switch (nregs) { 570a8502b37SRichard Henderson case 1: 571a8502b37SRichard Henderson if (size == 0) { 5723698747cSPeter Maydell return false; 5733698747cSPeter Maydell } 574a8502b37SRichard Henderson align = MO_ALIGN; 575a8502b37SRichard Henderson break; 576a8502b37SRichard Henderson case 2: 577a8502b37SRichard Henderson align = pow2_align(size + 1); 578a8502b37SRichard Henderson break; 579a8502b37SRichard Henderson case 3: 5803698747cSPeter Maydell return false; 581a8502b37SRichard Henderson case 4: 5823a661024SClément Chigot if (size == 2) { 5833a661024SClément Chigot align = pow2_align(3); 5843a661024SClément Chigot } else { 585a8502b37SRichard Henderson align = pow2_align(size + 2); 5863a661024SClément Chigot } 587a8502b37SRichard Henderson break; 588a8502b37SRichard Henderson default: 589a8502b37SRichard Henderson g_assert_not_reached(); 590a8502b37SRichard Henderson } 5913698747cSPeter Maydell } 5923698747cSPeter Maydell 5933698747cSPeter Maydell if (!vfp_access_check(s)) { 5943698747cSPeter Maydell return true; 5953698747cSPeter Maydell } 5963698747cSPeter Maydell 5973698747cSPeter Maydell /* 5983698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 5993698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 6003698747cSPeter Maydell */ 6013698747cSPeter Maydell stride = a->t ? 2 : 1; 6023698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 603a8502b37SRichard Henderson mop = size | align; 6043698747cSPeter Maydell tmp = tcg_temp_new_i32(); 6053698747cSPeter Maydell addr = tcg_temp_new_i32(); 6063698747cSPeter Maydell load_reg_var(s, addr, a->rn); 6073698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 608a8502b37SRichard Henderson gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); 6093698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 6103698747cSPeter Maydell /* 6113698747cSPeter Maydell * We cannot write 16 bytes at once because the 6123698747cSPeter Maydell * destination is unaligned. 6133698747cSPeter Maydell */ 614015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6153698747cSPeter Maydell 8, 8, tmp); 616015ee81aSRichard Henderson tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1), 617015ee81aSRichard Henderson neon_full_reg_offset(vd), 8, 8); 6183698747cSPeter Maydell } else { 619015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6203698747cSPeter Maydell vec_size, vec_size, tmp); 6213698747cSPeter Maydell } 6223698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 6233698747cSPeter Maydell vd += stride; 624a8502b37SRichard Henderson 625a8502b37SRichard Henderson /* Subsequent memory operations inherit alignment */ 626a8502b37SRichard Henderson mop &= ~MO_AMASK; 6273698747cSPeter Maydell } 6283698747cSPeter Maydell 6293698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 6303698747cSPeter Maydell 6313698747cSPeter Maydell return true; 6323698747cSPeter Maydell } 633123ce4e3SPeter Maydell 634123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 635123ce4e3SPeter Maydell { 636123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 637123ce4e3SPeter Maydell int reg; 638123ce4e3SPeter Maydell int nregs = a->n + 1; 639123ce4e3SPeter Maydell int vd = a->vd; 640123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 64188976ff0SRichard Henderson MemOp mop; 642123ce4e3SPeter Maydell 643123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 644123ce4e3SPeter Maydell return false; 645123ce4e3SPeter Maydell } 646123ce4e3SPeter Maydell 647123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 648123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 649123ce4e3SPeter Maydell return false; 650123ce4e3SPeter Maydell } 651123ce4e3SPeter Maydell 652123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 653123ce4e3SPeter Maydell switch (nregs) { 654123ce4e3SPeter Maydell case 1: 655c64ee036SPeter Maydell if (a->stride != 1) { 656c64ee036SPeter Maydell return false; 657c64ee036SPeter Maydell } 658123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 659a736cbc3SRichard Henderson (a->size == 2 && (a->align == 1 || a->align == 2))) { 660123ce4e3SPeter Maydell return false; 661123ce4e3SPeter Maydell } 662123ce4e3SPeter Maydell break; 663123ce4e3SPeter Maydell case 2: 664123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 665123ce4e3SPeter Maydell return false; 666123ce4e3SPeter Maydell } 667123ce4e3SPeter Maydell break; 66841c5a0f7SPeter Maydell case 3: 66941c5a0f7SPeter Maydell if (a->align != 0) { 67041c5a0f7SPeter Maydell return false; 67141c5a0f7SPeter Maydell } 67241c5a0f7SPeter Maydell break; 673123ce4e3SPeter Maydell case 4: 674a736cbc3SRichard Henderson if (a->size == 2 && a->align == 3) { 675123ce4e3SPeter Maydell return false; 676123ce4e3SPeter Maydell } 677123ce4e3SPeter Maydell break; 678123ce4e3SPeter Maydell default: 679d385a605SRichard Henderson g_assert_not_reached(); 680123ce4e3SPeter Maydell } 681123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 682123ce4e3SPeter Maydell /* 683123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 684123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 685123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 686123ce4e3SPeter Maydell */ 687123ce4e3SPeter Maydell return false; 688123ce4e3SPeter Maydell } 689123ce4e3SPeter Maydell 690123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 691123ce4e3SPeter Maydell return true; 692123ce4e3SPeter Maydell } 693123ce4e3SPeter Maydell 69488976ff0SRichard Henderson /* Pick up SCTLR settings */ 69588976ff0SRichard Henderson mop = finalize_memop(s, a->size); 69688976ff0SRichard Henderson 69788976ff0SRichard Henderson if (a->align) { 69888976ff0SRichard Henderson MemOp align_op; 69988976ff0SRichard Henderson 70088976ff0SRichard Henderson switch (nregs) { 70188976ff0SRichard Henderson case 1: 70288976ff0SRichard Henderson /* For VLD1, use natural alignment. */ 70388976ff0SRichard Henderson align_op = MO_ALIGN; 70488976ff0SRichard Henderson break; 70588976ff0SRichard Henderson case 2: 70688976ff0SRichard Henderson /* For VLD2, use double alignment. */ 70788976ff0SRichard Henderson align_op = pow2_align(a->size + 1); 70888976ff0SRichard Henderson break; 70988976ff0SRichard Henderson case 4: 71088976ff0SRichard Henderson if (a->size == MO_32) { 71188976ff0SRichard Henderson /* 71288976ff0SRichard Henderson * For VLD4.32, align = 1 is double alignment, align = 2 is 71388976ff0SRichard Henderson * quad alignment; align = 3 is rejected above. 71488976ff0SRichard Henderson */ 71588976ff0SRichard Henderson align_op = pow2_align(a->size + a->align); 71688976ff0SRichard Henderson } else { 71788976ff0SRichard Henderson /* For VLD4.8 and VLD.16, we want quad alignment. */ 71888976ff0SRichard Henderson align_op = pow2_align(a->size + 2); 71988976ff0SRichard Henderson } 72088976ff0SRichard Henderson break; 72188976ff0SRichard Henderson default: 72288976ff0SRichard Henderson /* For VLD3, the alignment field is zero and rejected above. */ 72388976ff0SRichard Henderson g_assert_not_reached(); 72488976ff0SRichard Henderson } 72588976ff0SRichard Henderson 72688976ff0SRichard Henderson mop = (mop & ~MO_AMASK) | align_op; 72788976ff0SRichard Henderson } 72888976ff0SRichard Henderson 729123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 730123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 731123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 73288976ff0SRichard Henderson 733123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 734123ce4e3SPeter Maydell if (a->l) { 73588976ff0SRichard Henderson gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop); 736123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 737123ce4e3SPeter Maydell } else { /* Store */ 738123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 73988976ff0SRichard Henderson gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop); 740123ce4e3SPeter Maydell } 741123ce4e3SPeter Maydell vd += a->stride; 742123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 74388976ff0SRichard Henderson 74488976ff0SRichard Henderson /* Subsequent memory operations inherit alignment */ 74588976ff0SRichard Henderson mop &= ~MO_AMASK; 746123ce4e3SPeter Maydell } 747123ce4e3SPeter Maydell 748123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 749123ce4e3SPeter Maydell 750123ce4e3SPeter Maydell return true; 751123ce4e3SPeter Maydell } 752a4e143acSPeter Maydell 753a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 754a4e143acSPeter Maydell { 755a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 756015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 757015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 758015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 759a4e143acSPeter Maydell 760a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 761a4e143acSPeter Maydell return false; 762a4e143acSPeter Maydell } 763a4e143acSPeter Maydell 764a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 765a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 766a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 767a4e143acSPeter Maydell return false; 768a4e143acSPeter Maydell } 769a4e143acSPeter Maydell 770a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 771a4e143acSPeter Maydell return false; 772a4e143acSPeter Maydell } 773a4e143acSPeter Maydell 774a4e143acSPeter Maydell if (!vfp_access_check(s)) { 775a4e143acSPeter Maydell return true; 776a4e143acSPeter Maydell } 777a4e143acSPeter Maydell 778a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 779a4e143acSPeter Maydell return true; 780a4e143acSPeter Maydell } 781a4e143acSPeter Maydell 782a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 783a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 784a4e143acSPeter Maydell { \ 785a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 786a4e143acSPeter Maydell } 787a4e143acSPeter Maydell 788a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 789a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 79035a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 79135a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 79235a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 79335a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 79435a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 7958161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 7968161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 797c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 798c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 799c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 800c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 80135a548edSPeter Maydell 80235a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 80335a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 80435a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 80535a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 80635a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 80735a548edSPeter Maydell { \ 80835a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 80935a548edSPeter Maydell } \ 81035a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 81135a548edSPeter Maydell 81235a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 81335a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 81435a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 81536b59310SPeter Maydell 81636b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 81736b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 81836b59310SPeter Maydell { \ 81936b59310SPeter Maydell if (a->size == 3) { \ 82036b59310SPeter Maydell return false; \ 82136b59310SPeter Maydell } \ 82236b59310SPeter Maydell return do_3same(s, a, FUNC); \ 82336b59310SPeter Maydell } 82436b59310SPeter Maydell 82536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 82636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 82736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 82836b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 8290de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 83027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 83127106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 8328161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 8337715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 8347715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 8357715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 8367715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 83702bd0cdbSPeter Maydell 83802bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 83902bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 84002bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 84102bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 84202bd0cdbSPeter Maydell { \ 84302bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 84402bd0cdbSPeter Maydell } \ 84502bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 84602bd0cdbSPeter Maydell 84702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 84802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 84902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 85002bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 85102bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 85202bd0cdbSPeter Maydell 853effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 854effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 855effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 856effa992fSRichard Henderson { \ 857effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 8580de34fd4SPeter Maydell } 8590de34fd4SPeter Maydell 860effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 861effa992fSRichard Henderson 8620de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 8630de34fd4SPeter Maydell { 8640de34fd4SPeter Maydell if (a->size != 0) { 8650de34fd4SPeter Maydell return false; 8660de34fd4SPeter Maydell } 8670de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 8680de34fd4SPeter Maydell } 869a0635695SPeter Maydell 870a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 871a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 872a0635695SPeter Maydell { \ 873a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 874a0635695SPeter Maydell return false; \ 875a0635695SPeter Maydell } \ 876a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 877a0635695SPeter Maydell return false; \ 878a0635695SPeter Maydell } \ 879a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 880a0635695SPeter Maydell } 881a0635695SPeter Maydell 882a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 883a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 88421290edfSPeter Maydell 885afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 886afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 887afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 888afc8b7d3SRichard Henderson { \ 889afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 890afc8b7d3SRichard Henderson return false; \ 891afc8b7d3SRichard Henderson } \ 892afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 89321290edfSPeter Maydell } 89421290edfSPeter Maydell 895afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 896afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 897afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 898afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 89921290edfSPeter Maydell 900effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 901effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 902effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 903effa992fSRichard Henderson { \ 904effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 905effa992fSRichard Henderson return false; \ 906effa992fSRichard Henderson } \ 907effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 90821290edfSPeter Maydell } 90921290edfSPeter Maydell 910effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 911effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 912effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 91335d4352fSPeter Maydell 91435d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 91535d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 91635d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 91735d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 91835d4352fSPeter Maydell { \ 91935d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 92035d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 92135d4352fSPeter Maydell } \ 92235d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 92335d4352fSPeter Maydell 92435d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 92535d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 92635d4352fSPeter Maydell { \ 92735d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 92835d4352fSPeter Maydell } \ 92935d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 93035d4352fSPeter Maydell 93135d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 93235d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 93335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 93435d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 93535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 93635d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 937cb294bcaSPeter Maydell 938cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 939cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 940cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 941cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 942cb294bcaSPeter Maydell { \ 943cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 944cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 945cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 946cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 947cb294bcaSPeter Maydell { 0 }, \ 948cb294bcaSPeter Maydell }; \ 949cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 950cb294bcaSPeter Maydell } \ 951cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 952cb294bcaSPeter Maydell { \ 953cb294bcaSPeter Maydell if (a->size > 2) { \ 954cb294bcaSPeter Maydell return false; \ 955cb294bcaSPeter Maydell } \ 956cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 957cb294bcaSPeter Maydell } 958cb294bcaSPeter Maydell 9596812dfdcSPeter Maydell /* 9606812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 9616812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 9626812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 9636812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 9646812dfdcSPeter Maydell */ 9656812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 9666812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 9676812dfdcSPeter Maydell { \ 9686812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 9696812dfdcSPeter Maydell } 9706812dfdcSPeter Maydell 9716812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 9726812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 9736812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 9746812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 9756812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9766812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9776812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9786812dfdcSPeter Maydell { \ 9796812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 9806812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9816812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9826812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9836812dfdcSPeter Maydell { 0 }, \ 9846812dfdcSPeter Maydell }; \ 9856812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 9866812dfdcSPeter Maydell } \ 9876812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9886812dfdcSPeter Maydell { \ 9896812dfdcSPeter Maydell if (a->size > 2) { \ 9906812dfdcSPeter Maydell return false; \ 9916812dfdcSPeter Maydell } \ 9926812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 9936812dfdcSPeter Maydell } 9946812dfdcSPeter Maydell 995cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 996cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 9978e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 9988e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 9998e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 10008e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 10016812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 10026812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 10036812dfdcSPeter Maydell 10046812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 10056812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 10066812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 10076812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 1008059c2398SPeter Maydell 1009059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 1010059c2398SPeter Maydell { 1011059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 1012059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1013059c2398SPeter Maydell 1014059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1015059c2398SPeter Maydell return false; 1016059c2398SPeter Maydell } 1017059c2398SPeter Maydell 1018059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1019059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1020059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1021059c2398SPeter Maydell return false; 1022059c2398SPeter Maydell } 1023059c2398SPeter Maydell 1024059c2398SPeter Maydell if (a->size == 3) { 1025059c2398SPeter Maydell return false; 1026059c2398SPeter Maydell } 1027059c2398SPeter Maydell 1028059c2398SPeter Maydell if (!vfp_access_check(s)) { 1029059c2398SPeter Maydell return true; 1030059c2398SPeter Maydell } 1031059c2398SPeter Maydell 1032059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1033059c2398SPeter Maydell 1034059c2398SPeter Maydell /* 1035059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 1036059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1037059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1038059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 1039059c2398SPeter Maydell */ 1040a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 1041a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 1042a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 1043a712266fSRichard Henderson 1044a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1045a712266fSRichard Henderson read_neon_element32(tmp2, a->vn, 1, MO_32); 1046059c2398SPeter Maydell fn(tmp, tmp, tmp2); 1047059c2398SPeter Maydell 1048a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 0, MO_32); 1049a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 1050059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 1051059c2398SPeter Maydell 1052a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 0, MO_32); 1053a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 1054a712266fSRichard Henderson 1055059c2398SPeter Maydell return true; 1056059c2398SPeter Maydell } 1057059c2398SPeter Maydell 1058059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 1059059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 1060059c2398SPeter Maydell { \ 1061059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 1062059c2398SPeter Maydell gen_helper_neon_##func##8, \ 1063059c2398SPeter Maydell gen_helper_neon_##func##16, \ 1064059c2398SPeter Maydell gen_helper_neon_##func##32, \ 1065059c2398SPeter Maydell }; \ 1066059c2398SPeter Maydell if (a->size > 2) { \ 1067059c2398SPeter Maydell return false; \ 1068059c2398SPeter Maydell } \ 1069059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 1070059c2398SPeter Maydell } 1071059c2398SPeter Maydell 1072059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 1073059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 1074059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 1075059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 1076059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 1077fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1078059c2398SPeter Maydell 1079059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1080059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1081059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1082059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1083fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 10847ecc28bcSPeter Maydell 10857ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 10867ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 10877ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 10887ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 10897ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 10907ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 10917ecc28bcSPeter Maydell { \ 10927ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 10937ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 10947ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 10957ecc28bcSPeter Maydell }; \ 10967ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 10977ecc28bcSPeter Maydell } \ 10987ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 10997ecc28bcSPeter Maydell { \ 11007ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 11017ecc28bcSPeter Maydell return false; \ 11027ecc28bcSPeter Maydell } \ 11037ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 11047ecc28bcSPeter Maydell } 11057ecc28bcSPeter Maydell 11067ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 11077ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1108a26a352bSPeter Maydell 1109e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1110e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1111a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1112a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1113a26a352bSPeter Maydell { \ 1114e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1115a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1116a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1117e4a6d4a6SPeter Maydell } 1118e4a6d4a6SPeter Maydell 1119e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1120e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1121e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1122a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1123a26a352bSPeter Maydell { \ 11246cf0f240SPeter Maydell if (a->size == MO_16) { \ 1125e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1126a26a352bSPeter Maydell return false; \ 1127a26a352bSPeter Maydell } \ 1128e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1129e4a6d4a6SPeter Maydell } \ 1130e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1131a26a352bSPeter Maydell } 1132a26a352bSPeter Maydell 1133a26a352bSPeter Maydell 1134e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1135e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1136e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1137e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 1138ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h) 1139ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h) 1140ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h) 1141bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h) 1142bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h) 1143e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h) 1144e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h) 1145e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h) 1146e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h) 1147cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h) 1148cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h) 1149ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h) 115040fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h) 1151ab978335SPeter Maydell 1152e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s) 1153e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h) 1154e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s) 1155e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h) 1156e22705bbSPeter Maydell 1157d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1158d5fdf9e9SPeter Maydell { 1159d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1160d5fdf9e9SPeter Maydell return false; 1161d5fdf9e9SPeter Maydell } 1162d5fdf9e9SPeter Maydell 11636cf0f240SPeter Maydell if (a->size == MO_16) { 1164e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1165d5fdf9e9SPeter Maydell return false; 1166d5fdf9e9SPeter Maydell } 1167e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp16_3s); 1168e22705bbSPeter Maydell } 1169e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp32_3s); 1170d5fdf9e9SPeter Maydell } 1171d5fdf9e9SPeter Maydell 1172d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1173d5fdf9e9SPeter Maydell { 1174d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1175d5fdf9e9SPeter Maydell return false; 1176d5fdf9e9SPeter Maydell } 1177d5fdf9e9SPeter Maydell 11786cf0f240SPeter Maydell if (a->size == MO_16) { 1179e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1180d5fdf9e9SPeter Maydell return false; 1181d5fdf9e9SPeter Maydell } 1182e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp16_3s); 1183e22705bbSPeter Maydell } 1184e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp32_3s); 1185d5fdf9e9SPeter Maydell } 1186d5fdf9e9SPeter Maydell 11871dc587eeSPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, 11881dc587eeSPeter Maydell gen_helper_gvec_3_ptr *fn) 1189ab978335SPeter Maydell { 11901dc587eeSPeter Maydell /* FP pairwise operations */ 1191ab978335SPeter Maydell TCGv_ptr fpstatus; 1192ab978335SPeter Maydell 1193ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1194ab978335SPeter Maydell return false; 1195ab978335SPeter Maydell } 1196ab978335SPeter Maydell 1197ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1198ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1199ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1200ab978335SPeter Maydell return false; 1201ab978335SPeter Maydell } 1202ab978335SPeter Maydell 1203ab978335SPeter Maydell if (!vfp_access_check(s)) { 1204ab978335SPeter Maydell return true; 1205ab978335SPeter Maydell } 1206ab978335SPeter Maydell 1207ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1208ab978335SPeter Maydell 1209ab978335SPeter Maydell 12106cf0f240SPeter Maydell fpstatus = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 12111dc587eeSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 12121dc587eeSPeter Maydell vfp_reg_offset(1, a->vn), 12131dc587eeSPeter Maydell vfp_reg_offset(1, a->vm), 12141dc587eeSPeter Maydell fpstatus, 8, 8, 0, fn); 1215ab978335SPeter Maydell 1216ab978335SPeter Maydell return true; 1217ab978335SPeter Maydell } 1218ab978335SPeter Maydell 1219ab978335SPeter Maydell /* 1220ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1221ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1222ab978335SPeter Maydell */ 1223ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1224ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1225ab978335SPeter Maydell { \ 12266cf0f240SPeter Maydell if (a->size == MO_16) { \ 12271dc587eeSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1228ab978335SPeter Maydell return false; \ 1229ab978335SPeter Maydell } \ 12301dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##h); \ 12311dc587eeSPeter Maydell } \ 12321dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##s); \ 1233ab978335SPeter Maydell } 1234ab978335SPeter Maydell 12351dc587eeSPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_neon_padd) 12361dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_neon_pmax) 12371dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_neon_pmin) 1238d3c8c736SPeter Maydell 1239d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1240d3c8c736SPeter Maydell { 1241d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1242d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1243015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1244015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 1245d3c8c736SPeter Maydell 1246d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1247d3c8c736SPeter Maydell return false; 1248d3c8c736SPeter Maydell } 1249d3c8c736SPeter Maydell 1250d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1251d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1252d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1253d3c8c736SPeter Maydell return false; 1254d3c8c736SPeter Maydell } 1255d3c8c736SPeter Maydell 1256d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1257d3c8c736SPeter Maydell return false; 1258d3c8c736SPeter Maydell } 1259d3c8c736SPeter Maydell 1260d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1261d3c8c736SPeter Maydell return true; 1262d3c8c736SPeter Maydell } 1263d3c8c736SPeter Maydell 1264d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1265d3c8c736SPeter Maydell return true; 1266d3c8c736SPeter Maydell } 1267d3c8c736SPeter Maydell 1268d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1269d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1270d3c8c736SPeter Maydell { \ 1271d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1272d3c8c736SPeter Maydell } \ 1273d3c8c736SPeter Maydell 1274d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1275d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1276434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1277434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1278434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1279434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1280434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1281434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1282434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 128366432d6bSPeter Maydell 128466432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 128566432d6bSPeter Maydell { 128666432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 128766432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 128866432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 128966432d6bSPeter Maydell } 129066432d6bSPeter Maydell 129166432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 129266432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 129366432d6bSPeter Maydell { 129466432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 129566432d6bSPeter Maydell } 129666432d6bSPeter Maydell 129766432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 129866432d6bSPeter Maydell { 129966432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 130066432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 130166432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 130266432d6bSPeter Maydell } else { 130366432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 130466432d6bSPeter Maydell } 130566432d6bSPeter Maydell } 130637bfce81SPeter Maydell 130737bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 130837bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 130937bfce81SPeter Maydell { 131037bfce81SPeter Maydell /* 131137bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 131237bfce81SPeter Maydell * function needs to be passed cpu_env. 131337bfce81SPeter Maydell */ 131437bfce81SPeter Maydell TCGv_i64 constimm; 131537bfce81SPeter Maydell int pass; 131637bfce81SPeter Maydell 131737bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 131837bfce81SPeter Maydell return false; 131937bfce81SPeter Maydell } 132037bfce81SPeter Maydell 132137bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 132237bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 132337bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 132437bfce81SPeter Maydell return false; 132537bfce81SPeter Maydell } 132637bfce81SPeter Maydell 132737bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 132837bfce81SPeter Maydell return false; 132937bfce81SPeter Maydell } 133037bfce81SPeter Maydell 133137bfce81SPeter Maydell if (!vfp_access_check(s)) { 133237bfce81SPeter Maydell return true; 133337bfce81SPeter Maydell } 133437bfce81SPeter Maydell 133537bfce81SPeter Maydell /* 133637bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 133737bfce81SPeter Maydell * by immediate using the variable shift operations. 133837bfce81SPeter Maydell */ 1339d9b47e97SRichard Henderson constimm = tcg_constant_i64(dup_const(a->size, a->shift)); 134037bfce81SPeter Maydell 134137bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 134237bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 134337bfce81SPeter Maydell 13440aa8e700SRichard Henderson read_neon_element64(tmp, a->vm, pass, MO_64); 134537bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 13460aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, pass, MO_64); 134737bfce81SPeter Maydell } 134837bfce81SPeter Maydell return true; 134937bfce81SPeter Maydell } 135037bfce81SPeter Maydell 135137bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 135237bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 135337bfce81SPeter Maydell { 135437bfce81SPeter Maydell /* 135537bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 135637bfce81SPeter Maydell * helper needs to be passed cpu_env. 135737bfce81SPeter Maydell */ 1358a712266fSRichard Henderson TCGv_i32 constimm, tmp; 135937bfce81SPeter Maydell int pass; 136037bfce81SPeter Maydell 136137bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 136237bfce81SPeter Maydell return false; 136337bfce81SPeter Maydell } 136437bfce81SPeter Maydell 136537bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 136637bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 136737bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 136837bfce81SPeter Maydell return false; 136937bfce81SPeter Maydell } 137037bfce81SPeter Maydell 137137bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 137237bfce81SPeter Maydell return false; 137337bfce81SPeter Maydell } 137437bfce81SPeter Maydell 137537bfce81SPeter Maydell if (!vfp_access_check(s)) { 137637bfce81SPeter Maydell return true; 137737bfce81SPeter Maydell } 137837bfce81SPeter Maydell 137937bfce81SPeter Maydell /* 138037bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 138137bfce81SPeter Maydell * by immediate using the variable shift operations. 138237bfce81SPeter Maydell */ 1383d9b47e97SRichard Henderson constimm = tcg_constant_i32(dup_const(a->size, a->shift)); 1384a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 138537bfce81SPeter Maydell 138637bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 1387a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 138837bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 1389a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 139037bfce81SPeter Maydell } 139137bfce81SPeter Maydell return true; 139237bfce81SPeter Maydell } 139337bfce81SPeter Maydell 139437bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 139537bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 139637bfce81SPeter Maydell { \ 139737bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 139837bfce81SPeter Maydell } \ 139937bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 140037bfce81SPeter Maydell { \ 140137bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 140237bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 140337bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 140437bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 140537bfce81SPeter Maydell }; \ 140637bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 140737bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 140837bfce81SPeter Maydell } 140937bfce81SPeter Maydell 141037bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 141137bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 141237bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1413712182d3SPeter Maydell 1414712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1415712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1416712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1417712182d3SPeter Maydell { 1418712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1419712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1420712182d3SPeter Maydell TCGv_i32 rd; 1421712182d3SPeter Maydell 1422712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1423712182d3SPeter Maydell return false; 1424712182d3SPeter Maydell } 1425712182d3SPeter Maydell 1426712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1427712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1428712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1429712182d3SPeter Maydell return false; 1430712182d3SPeter Maydell } 1431712182d3SPeter Maydell 1432712182d3SPeter Maydell if (a->vm & 1) { 1433712182d3SPeter Maydell return false; 1434712182d3SPeter Maydell } 1435712182d3SPeter Maydell 1436712182d3SPeter Maydell if (!vfp_access_check(s)) { 1437712182d3SPeter Maydell return true; 1438712182d3SPeter Maydell } 1439712182d3SPeter Maydell 1440712182d3SPeter Maydell /* 1441712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1442712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1443712182d3SPeter Maydell */ 1444d9b47e97SRichard Henderson constimm = tcg_constant_i64(-a->shift); 1445712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1446712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1447a712266fSRichard Henderson rd = tcg_temp_new_i32(); 1448712182d3SPeter Maydell 1449712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 14500aa8e700SRichard Henderson read_neon_element64(rm1, a->vm, 0, MO_64); 14510aa8e700SRichard Henderson read_neon_element64(rm2, a->vm, 1, MO_64); 1452712182d3SPeter Maydell 1453712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1454712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1455a712266fSRichard Henderson write_neon_element32(rd, a->vd, 0, MO_32); 1456712182d3SPeter Maydell 1457712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1458712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1459a712266fSRichard Henderson write_neon_element32(rd, a->vd, 1, MO_32); 1460712182d3SPeter Maydell 1461712182d3SPeter Maydell return true; 1462712182d3SPeter Maydell } 1463712182d3SPeter Maydell 1464712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1465712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1466712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1467712182d3SPeter Maydell { 1468712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1469712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1470712182d3SPeter Maydell TCGv_i64 rtmp; 1471712182d3SPeter Maydell uint32_t imm; 1472712182d3SPeter Maydell 1473712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1474712182d3SPeter Maydell return false; 1475712182d3SPeter Maydell } 1476712182d3SPeter Maydell 1477712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1478712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1479712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1480712182d3SPeter Maydell return false; 1481712182d3SPeter Maydell } 1482712182d3SPeter Maydell 1483712182d3SPeter Maydell if (a->vm & 1) { 1484712182d3SPeter Maydell return false; 1485712182d3SPeter Maydell } 1486712182d3SPeter Maydell 1487712182d3SPeter Maydell if (!vfp_access_check(s)) { 1488712182d3SPeter Maydell return true; 1489712182d3SPeter Maydell } 1490712182d3SPeter Maydell 1491712182d3SPeter Maydell /* 1492712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1493712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1494712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1495712182d3SPeter Maydell */ 1496712182d3SPeter Maydell if (a->size == 1) { 1497712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1498712182d3SPeter Maydell imm |= imm << 16; 1499712182d3SPeter Maydell } else { 1500712182d3SPeter Maydell /* size == 2 */ 1501712182d3SPeter Maydell imm = -a->shift; 1502712182d3SPeter Maydell } 1503d9b47e97SRichard Henderson constimm = tcg_constant_i32(imm); 1504712182d3SPeter Maydell 1505712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1506a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1507a712266fSRichard Henderson rm2 = tcg_temp_new_i32(); 1508a712266fSRichard Henderson rm3 = tcg_temp_new_i32(); 1509a712266fSRichard Henderson rm4 = tcg_temp_new_i32(); 1510a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 0, MO_32); 1511a712266fSRichard Henderson read_neon_element32(rm2, a->vm, 1, MO_32); 1512a712266fSRichard Henderson read_neon_element32(rm3, a->vm, 2, MO_32); 1513a712266fSRichard Henderson read_neon_element32(rm4, a->vm, 3, MO_32); 1514712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1515712182d3SPeter Maydell 1516712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1517712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1518712182d3SPeter Maydell 1519712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1520712182d3SPeter Maydell 1521712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1522a712266fSRichard Henderson write_neon_element32(rm1, a->vd, 0, MO_32); 1523712182d3SPeter Maydell 1524712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1525712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1526712182d3SPeter Maydell 1527712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1528712182d3SPeter Maydell 1529712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1530a712266fSRichard Henderson write_neon_element32(rm3, a->vd, 1, MO_32); 1531712182d3SPeter Maydell return true; 1532712182d3SPeter Maydell } 1533712182d3SPeter Maydell 1534712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1535712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1536712182d3SPeter Maydell { \ 1537712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1538712182d3SPeter Maydell } 1539712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1540712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1541712182d3SPeter Maydell { \ 1542712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1543712182d3SPeter Maydell } 1544712182d3SPeter Maydell 1545712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1546712182d3SPeter Maydell { 1547712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1548712182d3SPeter Maydell } 1549712182d3SPeter Maydell 1550712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1551712182d3SPeter Maydell { 1552712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1553712182d3SPeter Maydell } 1554712182d3SPeter Maydell 1555712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1556712182d3SPeter Maydell { 1557712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1558712182d3SPeter Maydell } 1559712182d3SPeter Maydell 1560712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1561712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1562712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1563712182d3SPeter Maydell 1564712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1565712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1566712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1567712182d3SPeter Maydell 1568712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1569712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1570712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1571712182d3SPeter Maydell 1572712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1573712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1574712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1575b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1576b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1577b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1578b4a3a77bSPeter Maydell 1579b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1580b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1581b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1582b4a3a77bSPeter Maydell 1583b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1584b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1585b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1586b4a3a77bSPeter Maydell 1587b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1588b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1589b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1590968bf842SPeter Maydell 1591968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1592968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1593968bf842SPeter Maydell { 1594968bf842SPeter Maydell TCGv_i64 tmp; 1595968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1596968bf842SPeter Maydell uint64_t widen_mask = 0; 1597968bf842SPeter Maydell 1598968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1599968bf842SPeter Maydell return false; 1600968bf842SPeter Maydell } 1601968bf842SPeter Maydell 1602968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1603968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1604968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1605968bf842SPeter Maydell return false; 1606968bf842SPeter Maydell } 1607968bf842SPeter Maydell 1608968bf842SPeter Maydell if (a->vd & 1) { 1609968bf842SPeter Maydell return false; 1610968bf842SPeter Maydell } 1611968bf842SPeter Maydell 1612968bf842SPeter Maydell if (!vfp_access_check(s)) { 1613968bf842SPeter Maydell return true; 1614968bf842SPeter Maydell } 1615968bf842SPeter Maydell 1616968bf842SPeter Maydell /* 1617968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1618968bf842SPeter Maydell * than the width of the source type, so after widening the input 1619968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1620968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1621968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1622968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1623968bf842SPeter Maydell */ 1624968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1625968bf842SPeter Maydell int esize = 8 << a->size; 1626968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1627968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1628968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1629968bf842SPeter Maydell } 1630968bf842SPeter Maydell 1631a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 1632a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1633a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 1634a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 1635968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1636968bf842SPeter Maydell 1637968bf842SPeter Maydell widenfn(tmp, rm0); 1638968bf842SPeter Maydell if (a->shift != 0) { 1639968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1640968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1641968bf842SPeter Maydell } 16420aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 0, MO_64); 1643968bf842SPeter Maydell 1644968bf842SPeter Maydell widenfn(tmp, rm1); 1645968bf842SPeter Maydell if (a->shift != 0) { 1646968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1647968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1648968bf842SPeter Maydell } 16490aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 1, MO_64); 1650968bf842SPeter Maydell return true; 1651968bf842SPeter Maydell } 1652968bf842SPeter Maydell 1653968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1654968bf842SPeter Maydell { 1655448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1656968bf842SPeter Maydell gen_helper_neon_widen_s8, 1657968bf842SPeter Maydell gen_helper_neon_widen_s16, 1658968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1659968bf842SPeter Maydell }; 1660968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1661968bf842SPeter Maydell } 1662968bf842SPeter Maydell 1663968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1664968bf842SPeter Maydell { 1665448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1666968bf842SPeter Maydell gen_helper_neon_widen_u8, 1667968bf842SPeter Maydell gen_helper_neon_widen_u16, 1668968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1669968bf842SPeter Maydell }; 1670968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1671968bf842SPeter Maydell } 16723da26f11SPeter Maydell 16733da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 16747b959c58SPeter Maydell gen_helper_gvec_2_ptr *fn) 16753da26f11SPeter Maydell { 16763da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 16777b959c58SPeter Maydell int vec_size = a->q ? 16 : 8; 1678015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1679015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 16807b959c58SPeter Maydell TCGv_ptr fpst; 16813da26f11SPeter Maydell 16823da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 16833da26f11SPeter Maydell return false; 16843da26f11SPeter Maydell } 16853da26f11SPeter Maydell 16860ae715c6SPeter Maydell if (a->size == MO_16) { 16877b959c58SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 16887b959c58SPeter Maydell return false; 16897b959c58SPeter Maydell } 16907b959c58SPeter Maydell } 16917b959c58SPeter Maydell 16923da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 16933da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 16943da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 16953da26f11SPeter Maydell return false; 16963da26f11SPeter Maydell } 16973da26f11SPeter Maydell 16983da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 16993da26f11SPeter Maydell return false; 17003da26f11SPeter Maydell } 17013da26f11SPeter Maydell 17023da26f11SPeter Maydell if (!vfp_access_check(s)) { 17033da26f11SPeter Maydell return true; 17043da26f11SPeter Maydell } 17053da26f11SPeter Maydell 17060ae715c6SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 17077b959c58SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn); 17083da26f11SPeter Maydell return true; 17093da26f11SPeter Maydell } 17103da26f11SPeter Maydell 17113da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 17123da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 17133da26f11SPeter Maydell { \ 17143da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 17153da26f11SPeter Maydell } 17163da26f11SPeter Maydell 17177b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 17187b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 17197b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 17207b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) 17212c35a39eSPeter Maydell 172224018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) 172324018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) 172424018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 172524018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) 172624018cf3SPeter Maydell 17272c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 17282c35a39eSPeter Maydell GVecGen2iFn *fn) 17292c35a39eSPeter Maydell { 17302c35a39eSPeter Maydell uint64_t imm; 17312c35a39eSPeter Maydell int reg_ofs, vec_size; 17322c35a39eSPeter Maydell 17332c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17342c35a39eSPeter Maydell return false; 17352c35a39eSPeter Maydell } 17362c35a39eSPeter Maydell 17372c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17382c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 17392c35a39eSPeter Maydell return false; 17402c35a39eSPeter Maydell } 17412c35a39eSPeter Maydell 17422c35a39eSPeter Maydell if (a->vd & a->q) { 17432c35a39eSPeter Maydell return false; 17442c35a39eSPeter Maydell } 17452c35a39eSPeter Maydell 17462c35a39eSPeter Maydell if (!vfp_access_check(s)) { 17472c35a39eSPeter Maydell return true; 17482c35a39eSPeter Maydell } 17492c35a39eSPeter Maydell 1750015ee81aSRichard Henderson reg_ofs = neon_full_reg_offset(a->vd); 17512c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 17522c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 17532c35a39eSPeter Maydell 17542c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 17552c35a39eSPeter Maydell return true; 17562c35a39eSPeter Maydell } 17572c35a39eSPeter Maydell 17582c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 17592c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 17602c35a39eSPeter Maydell { 17612c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 17622c35a39eSPeter Maydell } 17632c35a39eSPeter Maydell 17642c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 17652c35a39eSPeter Maydell { 17662c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 17672c35a39eSPeter Maydell GVecGen2iFn *fn; 17682c35a39eSPeter Maydell 17692c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 17702c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 17712c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 17722c35a39eSPeter Maydell } else { 17732c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 17742c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 17752c35a39eSPeter Maydell return false; 17762c35a39eSPeter Maydell } 17772c35a39eSPeter Maydell fn = gen_VMOV_1r; 17782c35a39eSPeter Maydell } 17792c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 17802c35a39eSPeter Maydell } 1781b28be095SPeter Maydell 1782b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1783b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1784b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 17858aab18a2SRichard Henderson int src1_mop, int src2_mop) 1786b28be095SPeter Maydell { 1787b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1788b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1789b28be095SPeter Maydell 1790b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1791b28be095SPeter Maydell return false; 1792b28be095SPeter Maydell } 1793b28be095SPeter Maydell 1794b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1795b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1796b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1797b28be095SPeter Maydell return false; 1798b28be095SPeter Maydell } 1799b28be095SPeter Maydell 18008aab18a2SRichard Henderson if (!opfn) { 1801b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1802b28be095SPeter Maydell return false; 1803b28be095SPeter Maydell } 1804b28be095SPeter Maydell 1805fc313c64SFrédéric Pétrot if ((a->vd & 1) || (src1_mop == MO_UQ && (a->vn & 1))) { 1806b28be095SPeter Maydell return false; 1807b28be095SPeter Maydell } 1808b28be095SPeter Maydell 1809b28be095SPeter Maydell if (!vfp_access_check(s)) { 1810b28be095SPeter Maydell return true; 1811b28be095SPeter Maydell } 1812b28be095SPeter Maydell 1813b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1814b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1815b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1816b28be095SPeter Maydell 18178aab18a2SRichard Henderson if (src1_mop >= 0) { 18188aab18a2SRichard Henderson read_neon_element64(rn0_64, a->vn, 0, src1_mop); 1819b28be095SPeter Maydell } else { 1820a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1821a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1822b28be095SPeter Maydell widenfn(rn0_64, tmp); 1823b28be095SPeter Maydell } 18248aab18a2SRichard Henderson if (src2_mop >= 0) { 18258aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 0, src2_mop); 18268aab18a2SRichard Henderson } else { 18278aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18288aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 18298aab18a2SRichard Henderson widenfn(rm_64, tmp); 18308aab18a2SRichard Henderson } 1831b28be095SPeter Maydell 1832b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1833b28be095SPeter Maydell 1834b28be095SPeter Maydell /* 1835b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1836b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1837b28be095SPeter Maydell */ 18388aab18a2SRichard Henderson if (src1_mop >= 0) { 18398aab18a2SRichard Henderson read_neon_element64(rn1_64, a->vn, 1, src1_mop); 1840b28be095SPeter Maydell } else { 1841a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1842a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 1, MO_32); 1843b28be095SPeter Maydell widenfn(rn1_64, tmp); 1844b28be095SPeter Maydell } 18458aab18a2SRichard Henderson if (src2_mop >= 0) { 18468aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 1, src2_mop); 18478aab18a2SRichard Henderson } else { 18488aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18498aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 1, MO_32); 18508aab18a2SRichard Henderson widenfn(rm_64, tmp); 18518aab18a2SRichard Henderson } 1852b28be095SPeter Maydell 18530aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 1854b28be095SPeter Maydell 1855b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 18560aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 1857b28be095SPeter Maydell 1858b28be095SPeter Maydell return true; 1859b28be095SPeter Maydell } 1860b28be095SPeter Maydell 18618aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN) \ 1862b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1863b28be095SPeter Maydell { \ 1864b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1865b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1866b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 18678aab18a2SRichard Henderson NULL, NULL, \ 1868b28be095SPeter Maydell }; \ 1869b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1870b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1871b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1872b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1873b28be095SPeter Maydell NULL, \ 1874b28be095SPeter Maydell }; \ 18758aab18a2SRichard Henderson int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \ 18768aab18a2SRichard Henderson return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \ 1877fc313c64SFrédéric Pétrot SRC1WIDE ? MO_UQ : narrow_mop, \ 18788aab18a2SRichard Henderson narrow_mop); \ 1879b28be095SPeter Maydell } 1880b28be095SPeter Maydell 18818aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN) 18828aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0) 18838aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN) 18848aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0) 18858aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN) 18868aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0) 18878aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN) 18888aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0) 18890fa1ab03SPeter Maydell 18900fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 18910fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 18920fa1ab03SPeter Maydell { 18930fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 18940fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 18950fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 18960fa1ab03SPeter Maydell 18970fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 18980fa1ab03SPeter Maydell return false; 18990fa1ab03SPeter Maydell } 19000fa1ab03SPeter Maydell 19010fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 19020fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 19030fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 19040fa1ab03SPeter Maydell return false; 19050fa1ab03SPeter Maydell } 19060fa1ab03SPeter Maydell 19070fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 19080fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 19090fa1ab03SPeter Maydell return false; 19100fa1ab03SPeter Maydell } 19110fa1ab03SPeter Maydell 19120fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 19130fa1ab03SPeter Maydell return false; 19140fa1ab03SPeter Maydell } 19150fa1ab03SPeter Maydell 19160fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 19170fa1ab03SPeter Maydell return true; 19180fa1ab03SPeter Maydell } 19190fa1ab03SPeter Maydell 19200fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 19210fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 19220fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 19230fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 19240fa1ab03SPeter Maydell 19250aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 0, MO_64); 19260aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 0, MO_64); 19270fa1ab03SPeter Maydell 19280fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19290fa1ab03SPeter Maydell 19300fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 19310fa1ab03SPeter Maydell 19320aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 1, MO_64); 19330aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 1, MO_64); 19340fa1ab03SPeter Maydell 19350fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19360fa1ab03SPeter Maydell 19370fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 19380fa1ab03SPeter Maydell 1939a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 1940a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 19410fa1ab03SPeter Maydell 19420fa1ab03SPeter Maydell return true; 19430fa1ab03SPeter Maydell } 19440fa1ab03SPeter Maydell 19450fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 19460fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 19470fa1ab03SPeter Maydell { \ 19480fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 19490fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 19500fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 19510fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 19520fa1ab03SPeter Maydell NULL, \ 19530fa1ab03SPeter Maydell }; \ 19540fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 19550fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 19560fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 19570fa1ab03SPeter Maydell EXTOP, \ 19580fa1ab03SPeter Maydell NULL, \ 19590fa1ab03SPeter Maydell }; \ 19600fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 19610fa1ab03SPeter Maydell } 19620fa1ab03SPeter Maydell 19630fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 19640fa1ab03SPeter Maydell { 19650fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 19660fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 19670fa1ab03SPeter Maydell } 19680fa1ab03SPeter Maydell 19690fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 19700fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 19710fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 19720fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 1973f5b28401SPeter Maydell 1974f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 1975f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 1976f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 1977f5b28401SPeter Maydell { 1978f5b28401SPeter Maydell /* 1979f5b28401SPeter Maydell * 3-regs different lengths, long operations. 1980f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 1981f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 1982f5b28401SPeter Maydell * that result into the double-width destination. 1983f5b28401SPeter Maydell */ 1984f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 1985f5b28401SPeter Maydell TCGv_i32 rn, rm; 1986f5b28401SPeter Maydell 1987f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1988f5b28401SPeter Maydell return false; 1989f5b28401SPeter Maydell } 1990f5b28401SPeter Maydell 1991f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1992f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1993f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1994f5b28401SPeter Maydell return false; 1995f5b28401SPeter Maydell } 1996f5b28401SPeter Maydell 1997f5b28401SPeter Maydell if (!opfn) { 1998f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1999f5b28401SPeter Maydell return false; 2000f5b28401SPeter Maydell } 2001f5b28401SPeter Maydell 2002f5b28401SPeter Maydell if (a->vd & 1) { 2003f5b28401SPeter Maydell return false; 2004f5b28401SPeter Maydell } 2005f5b28401SPeter Maydell 2006f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2007f5b28401SPeter Maydell return true; 2008f5b28401SPeter Maydell } 2009f5b28401SPeter Maydell 2010f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2011f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2012f5b28401SPeter Maydell 2013a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2014a712266fSRichard Henderson rm = tcg_temp_new_i32(); 2015a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 2016a712266fSRichard Henderson read_neon_element32(rm, a->vm, 0, MO_32); 2017f5b28401SPeter Maydell opfn(rd0, rn, rm); 2018f5b28401SPeter Maydell 2019a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 2020a712266fSRichard Henderson read_neon_element32(rm, a->vm, 1, MO_32); 2021f5b28401SPeter Maydell opfn(rd1, rn, rm); 2022f5b28401SPeter Maydell 2023f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2024f5b28401SPeter Maydell if (accfn) { 2025f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 20260aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 0, MO_64); 20279f1a5f93SRichard Henderson accfn(rd0, tmp, rd0); 20280aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 1, MO_64); 20299f1a5f93SRichard Henderson accfn(rd1, tmp, rd1); 2030f5b28401SPeter Maydell } 2031f5b28401SPeter Maydell 20329f1a5f93SRichard Henderson write_neon_element64(rd0, a->vd, 0, MO_64); 20339f1a5f93SRichard Henderson write_neon_element64(rd1, a->vd, 1, MO_64); 2034f5b28401SPeter Maydell 2035f5b28401SPeter Maydell return true; 2036f5b28401SPeter Maydell } 2037f5b28401SPeter Maydell 2038f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2039f5b28401SPeter Maydell { 2040f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2041f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2042f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2043f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2044f5b28401SPeter Maydell NULL, 2045f5b28401SPeter Maydell }; 2046f5b28401SPeter Maydell 2047f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2048f5b28401SPeter Maydell } 2049f5b28401SPeter Maydell 2050f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2051f5b28401SPeter Maydell { 2052f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2053f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2054f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2055f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2056f5b28401SPeter Maydell NULL, 2057f5b28401SPeter Maydell }; 2058f5b28401SPeter Maydell 2059f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2060f5b28401SPeter Maydell } 2061f5b28401SPeter Maydell 2062f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2063f5b28401SPeter Maydell { 2064f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2065f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2066f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2067f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2068f5b28401SPeter Maydell NULL, 2069f5b28401SPeter Maydell }; 2070f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2071f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2072f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2073f5b28401SPeter Maydell tcg_gen_add_i64, 2074f5b28401SPeter Maydell NULL, 2075f5b28401SPeter Maydell }; 2076f5b28401SPeter Maydell 2077f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2078f5b28401SPeter Maydell } 2079f5b28401SPeter Maydell 2080f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2081f5b28401SPeter Maydell { 2082f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2083f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2084f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2085f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2086f5b28401SPeter Maydell NULL, 2087f5b28401SPeter Maydell }; 2088f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2089f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2090f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2091f5b28401SPeter Maydell tcg_gen_add_i64, 2092f5b28401SPeter Maydell NULL, 2093f5b28401SPeter Maydell }; 2094f5b28401SPeter Maydell 2095f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2096f5b28401SPeter Maydell } 20973a1d9eb0SPeter Maydell 20983a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 20993a1d9eb0SPeter Maydell { 21003a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21013a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21023a1d9eb0SPeter Maydell 21033a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 21043a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21053a1d9eb0SPeter Maydell } 21063a1d9eb0SPeter Maydell 21073a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21083a1d9eb0SPeter Maydell { 21093a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21103a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21113a1d9eb0SPeter Maydell 21123a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 21133a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21143a1d9eb0SPeter Maydell } 21153a1d9eb0SPeter Maydell 21163a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 21173a1d9eb0SPeter Maydell { 21183a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21193a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 21203a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 21213a1d9eb0SPeter Maydell gen_mull_s32, 21223a1d9eb0SPeter Maydell NULL, 21233a1d9eb0SPeter Maydell }; 21243a1d9eb0SPeter Maydell 21253a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21263a1d9eb0SPeter Maydell } 21273a1d9eb0SPeter Maydell 21283a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 21293a1d9eb0SPeter Maydell { 21303a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21313a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 21323a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 21333a1d9eb0SPeter Maydell gen_mull_u32, 21343a1d9eb0SPeter Maydell NULL, 21353a1d9eb0SPeter Maydell }; 21363a1d9eb0SPeter Maydell 21373a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21383a1d9eb0SPeter Maydell } 21393a1d9eb0SPeter Maydell 21403a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 21413a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 21423a1d9eb0SPeter Maydell { \ 21433a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 21443a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 21453a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 21463a1d9eb0SPeter Maydell gen_##MULL##32, \ 21473a1d9eb0SPeter Maydell NULL, \ 21483a1d9eb0SPeter Maydell }; \ 21493a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 21503a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 21513a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 21523a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 21533a1d9eb0SPeter Maydell NULL, \ 21543a1d9eb0SPeter Maydell }; \ 21553a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 21563a1d9eb0SPeter Maydell } 21573a1d9eb0SPeter Maydell 21583a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 21593a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 21603a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 21613a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 21629546ca59SPeter Maydell 21639546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21649546ca59SPeter Maydell { 21659546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 21669546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 21679546ca59SPeter Maydell } 21689546ca59SPeter Maydell 21699546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21709546ca59SPeter Maydell { 21719546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 21729546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 21739546ca59SPeter Maydell } 21749546ca59SPeter Maydell 21759546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 21769546ca59SPeter Maydell { 21779546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21789546ca59SPeter Maydell NULL, 21799546ca59SPeter Maydell gen_VQDMULL_16, 21809546ca59SPeter Maydell gen_VQDMULL_32, 21819546ca59SPeter Maydell NULL, 21829546ca59SPeter Maydell }; 21839546ca59SPeter Maydell 21849546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21859546ca59SPeter Maydell } 21869546ca59SPeter Maydell 21879546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21889546ca59SPeter Maydell { 21899546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 21909546ca59SPeter Maydell } 21919546ca59SPeter Maydell 21929546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 21939546ca59SPeter Maydell { 21949546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 21959546ca59SPeter Maydell } 21969546ca59SPeter Maydell 21979546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 21989546ca59SPeter Maydell { 21999546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22009546ca59SPeter Maydell NULL, 22019546ca59SPeter Maydell gen_VQDMULL_16, 22029546ca59SPeter Maydell gen_VQDMULL_32, 22039546ca59SPeter Maydell NULL, 22049546ca59SPeter Maydell }; 22059546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22069546ca59SPeter Maydell NULL, 22079546ca59SPeter Maydell gen_VQDMLAL_acc_16, 22089546ca59SPeter Maydell gen_VQDMLAL_acc_32, 22099546ca59SPeter Maydell NULL, 22109546ca59SPeter Maydell }; 22119546ca59SPeter Maydell 22129546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22139546ca59SPeter Maydell } 22149546ca59SPeter Maydell 22159546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22169546ca59SPeter Maydell { 22179546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 22189546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22199546ca59SPeter Maydell } 22209546ca59SPeter Maydell 22219546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22229546ca59SPeter Maydell { 22239546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 22249546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22259546ca59SPeter Maydell } 22269546ca59SPeter Maydell 22279546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 22289546ca59SPeter Maydell { 22299546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22309546ca59SPeter Maydell NULL, 22319546ca59SPeter Maydell gen_VQDMULL_16, 22329546ca59SPeter Maydell gen_VQDMULL_32, 22339546ca59SPeter Maydell NULL, 22349546ca59SPeter Maydell }; 22359546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22369546ca59SPeter Maydell NULL, 22379546ca59SPeter Maydell gen_VQDMLSL_acc_16, 22389546ca59SPeter Maydell gen_VQDMLSL_acc_32, 22399546ca59SPeter Maydell NULL, 22409546ca59SPeter Maydell }; 22419546ca59SPeter Maydell 22429546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22439546ca59SPeter Maydell } 224418fb58d5SPeter Maydell 224518fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 224618fb58d5SPeter Maydell { 224718fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 224818fb58d5SPeter Maydell 224918fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 225018fb58d5SPeter Maydell return false; 225118fb58d5SPeter Maydell } 225218fb58d5SPeter Maydell 225318fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 225418fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 225518fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 225618fb58d5SPeter Maydell return false; 225718fb58d5SPeter Maydell } 225818fb58d5SPeter Maydell 225918fb58d5SPeter Maydell if (a->vd & 1) { 226018fb58d5SPeter Maydell return false; 226118fb58d5SPeter Maydell } 226218fb58d5SPeter Maydell 226318fb58d5SPeter Maydell switch (a->size) { 226418fb58d5SPeter Maydell case 0: 226518fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 226618fb58d5SPeter Maydell break; 226718fb58d5SPeter Maydell case 2: 226818fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 226918fb58d5SPeter Maydell return false; 227018fb58d5SPeter Maydell } 227118fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 227218fb58d5SPeter Maydell break; 227318fb58d5SPeter Maydell default: 227418fb58d5SPeter Maydell return false; 227518fb58d5SPeter Maydell } 227618fb58d5SPeter Maydell 227718fb58d5SPeter Maydell if (!vfp_access_check(s)) { 227818fb58d5SPeter Maydell return true; 227918fb58d5SPeter Maydell } 228018fb58d5SPeter Maydell 2281015ee81aSRichard Henderson tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd), 2282015ee81aSRichard Henderson neon_full_reg_offset(a->vn), 2283015ee81aSRichard Henderson neon_full_reg_offset(a->vm), 228418fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 228518fb58d5SPeter Maydell return true; 228618fb58d5SPeter Maydell } 228796fc80f5SPeter Maydell 228896fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 228996fc80f5SPeter Maydell { 229096fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 229196fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 229296fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 229396fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 229496fc80f5SPeter Maydell } 229596fc80f5SPeter Maydell 229696fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 229796fc80f5SPeter Maydell { 229896fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 229996fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 230096fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 230196fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 230296fc80f5SPeter Maydell } 230396fc80f5SPeter Maydell 230496fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 230596fc80f5SPeter Maydell { 2306a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 2307a712266fSRichard Henderson if (size == MO_16) { 2308a712266fSRichard Henderson read_neon_element32(tmp, reg & 7, reg >> 4, MO_32); 230996fc80f5SPeter Maydell if (reg & 8) { 231096fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 231196fc80f5SPeter Maydell } else { 231296fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 231396fc80f5SPeter Maydell } 231496fc80f5SPeter Maydell } else { 2315a712266fSRichard Henderson read_neon_element32(tmp, reg & 15, reg >> 4, MO_32); 231696fc80f5SPeter Maydell } 231796fc80f5SPeter Maydell return tmp; 231896fc80f5SPeter Maydell } 231996fc80f5SPeter Maydell 232096fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 232196fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 232296fc80f5SPeter Maydell { 232396fc80f5SPeter Maydell /* 232496fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 232596fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 232696fc80f5SPeter Maydell * perform an accumulation operation of that result into the 232796fc80f5SPeter Maydell * destination. 232896fc80f5SPeter Maydell */ 2329a712266fSRichard Henderson TCGv_i32 scalar, tmp; 233096fc80f5SPeter Maydell int pass; 233196fc80f5SPeter Maydell 233296fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 233396fc80f5SPeter Maydell return false; 233496fc80f5SPeter Maydell } 233596fc80f5SPeter Maydell 233696fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 233796fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 233896fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 233996fc80f5SPeter Maydell return false; 234096fc80f5SPeter Maydell } 234196fc80f5SPeter Maydell 234296fc80f5SPeter Maydell if (!opfn) { 234396fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 234496fc80f5SPeter Maydell return false; 234596fc80f5SPeter Maydell } 234696fc80f5SPeter Maydell 234796fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 234896fc80f5SPeter Maydell return false; 234996fc80f5SPeter Maydell } 235096fc80f5SPeter Maydell 235196fc80f5SPeter Maydell if (!vfp_access_check(s)) { 235296fc80f5SPeter Maydell return true; 235396fc80f5SPeter Maydell } 235496fc80f5SPeter Maydell 235596fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2356a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 235796fc80f5SPeter Maydell 235896fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2359a712266fSRichard Henderson read_neon_element32(tmp, a->vn, pass, MO_32); 236096fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 236196fc80f5SPeter Maydell if (accfn) { 2362a712266fSRichard Henderson TCGv_i32 rd = tcg_temp_new_i32(); 2363a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 236496fc80f5SPeter Maydell accfn(tmp, rd, tmp); 236596fc80f5SPeter Maydell } 2366a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 236796fc80f5SPeter Maydell } 236896fc80f5SPeter Maydell return true; 236996fc80f5SPeter Maydell } 237096fc80f5SPeter Maydell 237196fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 237296fc80f5SPeter Maydell { 237396fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 237496fc80f5SPeter Maydell NULL, 237596fc80f5SPeter Maydell gen_helper_neon_mul_u16, 237696fc80f5SPeter Maydell tcg_gen_mul_i32, 237796fc80f5SPeter Maydell NULL, 237896fc80f5SPeter Maydell }; 237996fc80f5SPeter Maydell 238096fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 238196fc80f5SPeter Maydell } 238296fc80f5SPeter Maydell 238396fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 238496fc80f5SPeter Maydell { 238596fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 238696fc80f5SPeter Maydell NULL, 238796fc80f5SPeter Maydell gen_helper_neon_mul_u16, 238896fc80f5SPeter Maydell tcg_gen_mul_i32, 238996fc80f5SPeter Maydell NULL, 239096fc80f5SPeter Maydell }; 239196fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 239296fc80f5SPeter Maydell NULL, 239396fc80f5SPeter Maydell gen_helper_neon_add_u16, 239496fc80f5SPeter Maydell tcg_gen_add_i32, 239596fc80f5SPeter Maydell NULL, 239696fc80f5SPeter Maydell }; 239796fc80f5SPeter Maydell 239896fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 239996fc80f5SPeter Maydell } 240096fc80f5SPeter Maydell 240196fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 240296fc80f5SPeter Maydell { 240396fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 240496fc80f5SPeter Maydell NULL, 240596fc80f5SPeter Maydell gen_helper_neon_mul_u16, 240696fc80f5SPeter Maydell tcg_gen_mul_i32, 240796fc80f5SPeter Maydell NULL, 240896fc80f5SPeter Maydell }; 240996fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 241096fc80f5SPeter Maydell NULL, 241196fc80f5SPeter Maydell gen_helper_neon_sub_u16, 241296fc80f5SPeter Maydell tcg_gen_sub_i32, 241396fc80f5SPeter Maydell NULL, 241496fc80f5SPeter Maydell }; 241596fc80f5SPeter Maydell 241696fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 241796fc80f5SPeter Maydell } 241885ac9aefSPeter Maydell 2419fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, 2420fc8ae790SPeter Maydell gen_helper_gvec_3_ptr *fn) 2421fc8ae790SPeter Maydell { 2422fc8ae790SPeter Maydell /* Two registers and a scalar, using gvec */ 2423fc8ae790SPeter Maydell int vec_size = a->q ? 16 : 8; 2424015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 2425015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 2426fc8ae790SPeter Maydell int rm_ofs; 2427fc8ae790SPeter Maydell int idx; 2428fc8ae790SPeter Maydell TCGv_ptr fpstatus; 2429fc8ae790SPeter Maydell 2430fc8ae790SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2431fc8ae790SPeter Maydell return false; 2432fc8ae790SPeter Maydell } 2433fc8ae790SPeter Maydell 2434fc8ae790SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2435fc8ae790SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2436fc8ae790SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2437fc8ae790SPeter Maydell return false; 2438fc8ae790SPeter Maydell } 2439fc8ae790SPeter Maydell 2440fc8ae790SPeter Maydell if (!fn) { 2441fc8ae790SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2442fc8ae790SPeter Maydell return false; 2443fc8ae790SPeter Maydell } 2444fc8ae790SPeter Maydell 2445fc8ae790SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2446fc8ae790SPeter Maydell return false; 2447fc8ae790SPeter Maydell } 2448fc8ae790SPeter Maydell 2449fc8ae790SPeter Maydell if (!vfp_access_check(s)) { 2450fc8ae790SPeter Maydell return true; 2451fc8ae790SPeter Maydell } 2452fc8ae790SPeter Maydell 2453fc8ae790SPeter Maydell /* a->vm is M:Vm, which encodes both register and index */ 2454fc8ae790SPeter Maydell idx = extract32(a->vm, a->size + 2, 2); 2455fc8ae790SPeter Maydell a->vm = extract32(a->vm, 0, a->size + 2); 2456015ee81aSRichard Henderson rm_ofs = neon_full_reg_offset(a->vm); 2457fc8ae790SPeter Maydell 2458fc8ae790SPeter Maydell fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD); 2459fc8ae790SPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus, 2460fc8ae790SPeter Maydell vec_size, vec_size, idx, fn); 2461fc8ae790SPeter Maydell return true; 2462fc8ae790SPeter Maydell } 2463fc8ae790SPeter Maydell 2464fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC) \ 2465fc8ae790SPeter Maydell static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \ 246685ac9aefSPeter Maydell { \ 2467fc8ae790SPeter Maydell static gen_helper_gvec_3_ptr * const opfn[] = { \ 2468fc8ae790SPeter Maydell NULL, \ 2469fc8ae790SPeter Maydell gen_helper_##FUNC##_h, \ 2470fc8ae790SPeter Maydell gen_helper_##FUNC##_s, \ 2471fc8ae790SPeter Maydell NULL, \ 2472fc8ae790SPeter Maydell }; \ 2473fc8ae790SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \ 2474fc8ae790SPeter Maydell return false; \ 2475fc8ae790SPeter Maydell } \ 2476fc8ae790SPeter Maydell return do_2scalar_fp_vec(s, a, opfn[a->size]); \ 247785ac9aefSPeter Maydell } 247885ac9aefSPeter Maydell 2479fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx) 2480fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx) 2481fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx) 2482b2fc7be9SPeter Maydell 2483b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2484b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2485b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2486b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2487b2fc7be9SPeter Maydell 2488b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2489b2fc7be9SPeter Maydell { 2490b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2491b2fc7be9SPeter Maydell NULL, 2492b2fc7be9SPeter Maydell gen_VQDMULH_16, 2493b2fc7be9SPeter Maydell gen_VQDMULH_32, 2494b2fc7be9SPeter Maydell NULL, 2495b2fc7be9SPeter Maydell }; 2496b2fc7be9SPeter Maydell 2497b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2498b2fc7be9SPeter Maydell } 2499b2fc7be9SPeter Maydell 2500b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2501b2fc7be9SPeter Maydell { 2502b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2503b2fc7be9SPeter Maydell NULL, 2504b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2505b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2506b2fc7be9SPeter Maydell NULL, 2507b2fc7be9SPeter Maydell }; 2508b2fc7be9SPeter Maydell 2509b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2510b2fc7be9SPeter Maydell } 2511aa318f5bSPeter Maydell 2512aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2513aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2514aa318f5bSPeter Maydell { 2515aa318f5bSPeter Maydell /* 2516aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2517aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2518aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2519aa318f5bSPeter Maydell */ 2520a712266fSRichard Henderson TCGv_i32 scalar, rn, rd; 2521aa318f5bSPeter Maydell int pass; 2522aa318f5bSPeter Maydell 2523aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2524aa318f5bSPeter Maydell return false; 2525aa318f5bSPeter Maydell } 2526aa318f5bSPeter Maydell 2527aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2528aa318f5bSPeter Maydell return false; 2529aa318f5bSPeter Maydell } 2530aa318f5bSPeter Maydell 2531aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2532aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2533aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2534aa318f5bSPeter Maydell return false; 2535aa318f5bSPeter Maydell } 2536aa318f5bSPeter Maydell 2537aa318f5bSPeter Maydell if (!opfn) { 2538aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2539aa318f5bSPeter Maydell return false; 2540aa318f5bSPeter Maydell } 2541aa318f5bSPeter Maydell 2542aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2543aa318f5bSPeter Maydell return false; 2544aa318f5bSPeter Maydell } 2545aa318f5bSPeter Maydell 2546aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2547aa318f5bSPeter Maydell return true; 2548aa318f5bSPeter Maydell } 2549aa318f5bSPeter Maydell 2550aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2551a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2552a712266fSRichard Henderson rd = tcg_temp_new_i32(); 2553aa318f5bSPeter Maydell 2554aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2555a712266fSRichard Henderson read_neon_element32(rn, a->vn, pass, MO_32); 2556a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 2557aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2558a712266fSRichard Henderson write_neon_element32(rd, a->vd, pass, MO_32); 2559aa318f5bSPeter Maydell } 2560aa318f5bSPeter Maydell return true; 2561aa318f5bSPeter Maydell } 2562aa318f5bSPeter Maydell 2563aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2564aa318f5bSPeter Maydell { 2565aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2566aa318f5bSPeter Maydell NULL, 2567aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2568aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2569aa318f5bSPeter Maydell NULL, 2570aa318f5bSPeter Maydell }; 2571aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2572aa318f5bSPeter Maydell } 2573aa318f5bSPeter Maydell 2574aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2575aa318f5bSPeter Maydell { 2576aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2577aa318f5bSPeter Maydell NULL, 2578aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2579aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2580aa318f5bSPeter Maydell NULL, 2581aa318f5bSPeter Maydell }; 2582aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2583aa318f5bSPeter Maydell } 258477e576a9SPeter Maydell 258577e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 258677e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 258777e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 258877e576a9SPeter Maydell { 258977e576a9SPeter Maydell /* 259077e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 259177e576a9SPeter Maydell * operation on the input elements and the scalar which produces 259277e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 259377e576a9SPeter Maydell * operation of that result into the destination. 259477e576a9SPeter Maydell */ 259577e576a9SPeter Maydell TCGv_i32 scalar, rn; 259677e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 259777e576a9SPeter Maydell 259877e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 259977e576a9SPeter Maydell return false; 260077e576a9SPeter Maydell } 260177e576a9SPeter Maydell 260277e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 260377e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 260477e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 260577e576a9SPeter Maydell return false; 260677e576a9SPeter Maydell } 260777e576a9SPeter Maydell 260877e576a9SPeter Maydell if (!opfn) { 260977e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 261077e576a9SPeter Maydell return false; 261177e576a9SPeter Maydell } 261277e576a9SPeter Maydell 261377e576a9SPeter Maydell if (a->vd & 1) { 261477e576a9SPeter Maydell return false; 261577e576a9SPeter Maydell } 261677e576a9SPeter Maydell 261777e576a9SPeter Maydell if (!vfp_access_check(s)) { 261877e576a9SPeter Maydell return true; 261977e576a9SPeter Maydell } 262077e576a9SPeter Maydell 262177e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 262277e576a9SPeter Maydell 262377e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 2624a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2625a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 262677e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 262777e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 262877e576a9SPeter Maydell 2629a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 263077e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 263177e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 263277e576a9SPeter Maydell 263377e576a9SPeter Maydell if (accfn) { 263477e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 26350aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 0, MO_64); 26369f1a5f93SRichard Henderson accfn(rn0_64, t64, rn0_64); 26370aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 1, MO_64); 26389f1a5f93SRichard Henderson accfn(rn1_64, t64, rn1_64); 26399f1a5f93SRichard Henderson } 26409f1a5f93SRichard Henderson 26410aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 26420aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 264377e576a9SPeter Maydell return true; 264477e576a9SPeter Maydell } 264577e576a9SPeter Maydell 264677e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 264777e576a9SPeter Maydell { 264877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 264977e576a9SPeter Maydell NULL, 265077e576a9SPeter Maydell gen_helper_neon_mull_s16, 265177e576a9SPeter Maydell gen_mull_s32, 265277e576a9SPeter Maydell NULL, 265377e576a9SPeter Maydell }; 265477e576a9SPeter Maydell 265577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 265677e576a9SPeter Maydell } 265777e576a9SPeter Maydell 265877e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 265977e576a9SPeter Maydell { 266077e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 266177e576a9SPeter Maydell NULL, 266277e576a9SPeter Maydell gen_helper_neon_mull_u16, 266377e576a9SPeter Maydell gen_mull_u32, 266477e576a9SPeter Maydell NULL, 266577e576a9SPeter Maydell }; 266677e576a9SPeter Maydell 266777e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 266877e576a9SPeter Maydell } 266977e576a9SPeter Maydell 267077e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 267177e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 267277e576a9SPeter Maydell { \ 267377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 267477e576a9SPeter Maydell NULL, \ 267577e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 267677e576a9SPeter Maydell gen_##MULL##32, \ 267777e576a9SPeter Maydell NULL, \ 267877e576a9SPeter Maydell }; \ 267977e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 268077e576a9SPeter Maydell NULL, \ 268177e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 268277e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 268377e576a9SPeter Maydell NULL, \ 268477e576a9SPeter Maydell }; \ 268577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 268677e576a9SPeter Maydell } 268777e576a9SPeter Maydell 268877e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 268977e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 269077e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 269177e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 269277e576a9SPeter Maydell 269377e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 269477e576a9SPeter Maydell { 269577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 269677e576a9SPeter Maydell NULL, 269777e576a9SPeter Maydell gen_VQDMULL_16, 269877e576a9SPeter Maydell gen_VQDMULL_32, 269977e576a9SPeter Maydell NULL, 270077e576a9SPeter Maydell }; 270177e576a9SPeter Maydell 270277e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 270377e576a9SPeter Maydell } 270477e576a9SPeter Maydell 270577e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 270677e576a9SPeter Maydell { 270777e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 270877e576a9SPeter Maydell NULL, 270977e576a9SPeter Maydell gen_VQDMULL_16, 271077e576a9SPeter Maydell gen_VQDMULL_32, 271177e576a9SPeter Maydell NULL, 271277e576a9SPeter Maydell }; 271377e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 271477e576a9SPeter Maydell NULL, 271577e576a9SPeter Maydell gen_VQDMLAL_acc_16, 271677e576a9SPeter Maydell gen_VQDMLAL_acc_32, 271777e576a9SPeter Maydell NULL, 271877e576a9SPeter Maydell }; 271977e576a9SPeter Maydell 272077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 272177e576a9SPeter Maydell } 272277e576a9SPeter Maydell 272377e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 272477e576a9SPeter Maydell { 272577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 272677e576a9SPeter Maydell NULL, 272777e576a9SPeter Maydell gen_VQDMULL_16, 272877e576a9SPeter Maydell gen_VQDMULL_32, 272977e576a9SPeter Maydell NULL, 273077e576a9SPeter Maydell }; 273177e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 273277e576a9SPeter Maydell NULL, 273377e576a9SPeter Maydell gen_VQDMLSL_acc_16, 273477e576a9SPeter Maydell gen_VQDMLSL_acc_32, 273577e576a9SPeter Maydell NULL, 273677e576a9SPeter Maydell }; 273777e576a9SPeter Maydell 273877e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 273977e576a9SPeter Maydell } 27400aad761fSPeter Maydell 27410aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 27420aad761fSPeter Maydell { 27430aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 27440aad761fSPeter Maydell return false; 27450aad761fSPeter Maydell } 27460aad761fSPeter Maydell 27470aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 27480aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 27490aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 27500aad761fSPeter Maydell return false; 27510aad761fSPeter Maydell } 27520aad761fSPeter Maydell 27530aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 27540aad761fSPeter Maydell return false; 27550aad761fSPeter Maydell } 27560aad761fSPeter Maydell 27570aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 27580aad761fSPeter Maydell return false; 27590aad761fSPeter Maydell } 27600aad761fSPeter Maydell 27610aad761fSPeter Maydell if (!vfp_access_check(s)) { 27620aad761fSPeter Maydell return true; 27630aad761fSPeter Maydell } 27640aad761fSPeter Maydell 27650aad761fSPeter Maydell if (!a->q) { 27660aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 27670aad761fSPeter Maydell TCGv_i64 left, right, dest; 27680aad761fSPeter Maydell 27690aad761fSPeter Maydell left = tcg_temp_new_i64(); 27700aad761fSPeter Maydell right = tcg_temp_new_i64(); 27710aad761fSPeter Maydell dest = tcg_temp_new_i64(); 27720aad761fSPeter Maydell 27730aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 27740aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 27750aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 27760aa8e700SRichard Henderson write_neon_element64(dest, a->vd, 0, MO_64); 27770aad761fSPeter Maydell } else { 27780aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 27790aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 27800aad761fSPeter Maydell 27810aad761fSPeter Maydell left = tcg_temp_new_i64(); 27820aad761fSPeter Maydell middle = tcg_temp_new_i64(); 27830aad761fSPeter Maydell right = tcg_temp_new_i64(); 27840aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 27850aad761fSPeter Maydell destright = tcg_temp_new_i64(); 27860aad761fSPeter Maydell 27870aad761fSPeter Maydell if (a->imm < 8) { 27880aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 27890aa8e700SRichard Henderson read_neon_element64(middle, a->vn, 1, MO_64); 27900aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 27910aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 27920aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 27930aad761fSPeter Maydell } else { 27940aa8e700SRichard Henderson read_neon_element64(right, a->vn, 1, MO_64); 27950aa8e700SRichard Henderson read_neon_element64(middle, a->vm, 0, MO_64); 27960aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 27970aa8e700SRichard Henderson read_neon_element64(left, a->vm, 1, MO_64); 27980aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 27990aad761fSPeter Maydell } 28000aad761fSPeter Maydell 28010aa8e700SRichard Henderson write_neon_element64(destright, a->vd, 0, MO_64); 28020aa8e700SRichard Henderson write_neon_element64(destleft, a->vd, 1, MO_64); 28030aad761fSPeter Maydell } 28040aad761fSPeter Maydell return true; 28050aad761fSPeter Maydell } 280654e96c74SPeter Maydell 280754e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 280854e96c74SPeter Maydell { 2809604cef3eSRichard Henderson TCGv_i64 val, def; 2810604cef3eSRichard Henderson TCGv_i32 desc; 281154e96c74SPeter Maydell 281254e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 281354e96c74SPeter Maydell return false; 281454e96c74SPeter Maydell } 281554e96c74SPeter Maydell 281654e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 281754e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 281854e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 281954e96c74SPeter Maydell return false; 282054e96c74SPeter Maydell } 282154e96c74SPeter Maydell 2822604cef3eSRichard Henderson if ((a->vn + a->len + 1) > 32) { 282354e96c74SPeter Maydell /* 282454e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 282554e96c74SPeter Maydell * helper function running off the end of the register file. 282654e96c74SPeter Maydell */ 282754e96c74SPeter Maydell return false; 282854e96c74SPeter Maydell } 2829a712266fSRichard Henderson 2830b6c56c8aSPeter Maydell if (!vfp_access_check(s)) { 2831b6c56c8aSPeter Maydell return true; 2832b6c56c8aSPeter Maydell } 2833b6c56c8aSPeter Maydell 2834d9b47e97SRichard Henderson desc = tcg_constant_i32((a->vn << 2) | a->len); 2835604cef3eSRichard Henderson def = tcg_temp_new_i64(); 283654e96c74SPeter Maydell if (a->op) { 2837604cef3eSRichard Henderson read_neon_element64(def, a->vd, 0, MO_64); 283854e96c74SPeter Maydell } else { 2839604cef3eSRichard Henderson tcg_gen_movi_i64(def, 0); 284054e96c74SPeter Maydell } 2841604cef3eSRichard Henderson val = tcg_temp_new_i64(); 2842604cef3eSRichard Henderson read_neon_element64(val, a->vm, 0, MO_64); 2843a712266fSRichard Henderson 2844604cef3eSRichard Henderson gen_helper_neon_tbl(val, cpu_env, desc, val, def); 2845604cef3eSRichard Henderson write_neon_element64(val, a->vd, 0, MO_64); 284654e96c74SPeter Maydell return true; 284754e96c74SPeter Maydell } 28489aaa23c2SPeter Maydell 28499aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 28509aaa23c2SPeter Maydell { 28519aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 28529aaa23c2SPeter Maydell return false; 28539aaa23c2SPeter Maydell } 28549aaa23c2SPeter Maydell 28559aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28569aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28579aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 28589aaa23c2SPeter Maydell return false; 28599aaa23c2SPeter Maydell } 28609aaa23c2SPeter Maydell 28619aaa23c2SPeter Maydell if (a->vd & a->q) { 28629aaa23c2SPeter Maydell return false; 28639aaa23c2SPeter Maydell } 28649aaa23c2SPeter Maydell 28659aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 28669aaa23c2SPeter Maydell return true; 28679aaa23c2SPeter Maydell } 28689aaa23c2SPeter Maydell 2869015ee81aSRichard Henderson tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd), 28709aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 28719aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 28729aaa23c2SPeter Maydell return true; 28739aaa23c2SPeter Maydell } 2874353d2b85SPeter Maydell 2875353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 2876353d2b85SPeter Maydell { 2877353d2b85SPeter Maydell int pass, half; 2878a712266fSRichard Henderson TCGv_i32 tmp[2]; 2879353d2b85SPeter Maydell 2880353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2881353d2b85SPeter Maydell return false; 2882353d2b85SPeter Maydell } 2883353d2b85SPeter Maydell 2884353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2885353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2886353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 2887353d2b85SPeter Maydell return false; 2888353d2b85SPeter Maydell } 2889353d2b85SPeter Maydell 2890353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 2891353d2b85SPeter Maydell return false; 2892353d2b85SPeter Maydell } 2893353d2b85SPeter Maydell 2894353d2b85SPeter Maydell if (a->size == 3) { 2895353d2b85SPeter Maydell return false; 2896353d2b85SPeter Maydell } 2897353d2b85SPeter Maydell 2898353d2b85SPeter Maydell if (!vfp_access_check(s)) { 2899353d2b85SPeter Maydell return true; 2900353d2b85SPeter Maydell } 2901353d2b85SPeter Maydell 2902a712266fSRichard Henderson tmp[0] = tcg_temp_new_i32(); 2903a712266fSRichard Henderson tmp[1] = tcg_temp_new_i32(); 2904353d2b85SPeter Maydell 2905a712266fSRichard Henderson for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 2906353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 2907a712266fSRichard Henderson read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32); 2908353d2b85SPeter Maydell switch (a->size) { 2909353d2b85SPeter Maydell case 0: 2910353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 2911353d2b85SPeter Maydell break; 2912353d2b85SPeter Maydell case 1: 29138ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 2914353d2b85SPeter Maydell break; 2915353d2b85SPeter Maydell case 2: 2916353d2b85SPeter Maydell break; 2917353d2b85SPeter Maydell default: 2918353d2b85SPeter Maydell g_assert_not_reached(); 2919353d2b85SPeter Maydell } 2920353d2b85SPeter Maydell } 2921a712266fSRichard Henderson write_neon_element32(tmp[1], a->vd, pass * 2, MO_32); 2922a712266fSRichard Henderson write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32); 2923353d2b85SPeter Maydell } 2924353d2b85SPeter Maydell return true; 2925353d2b85SPeter Maydell } 29266106af3aSPeter Maydell 29276106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 29286106af3aSPeter Maydell NeonGenWidenFn *widenfn, 29296106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 29306106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 29316106af3aSPeter Maydell { 29326106af3aSPeter Maydell /* 29336106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 29346106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 29356106af3aSPeter Maydell * into the destination with the accfn. 29366106af3aSPeter Maydell */ 29376106af3aSPeter Maydell int pass; 29386106af3aSPeter Maydell 29396106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 29406106af3aSPeter Maydell return false; 29416106af3aSPeter Maydell } 29426106af3aSPeter Maydell 29436106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 29446106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 29456106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 29466106af3aSPeter Maydell return false; 29476106af3aSPeter Maydell } 29486106af3aSPeter Maydell 29496106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 29506106af3aSPeter Maydell return false; 29516106af3aSPeter Maydell } 29526106af3aSPeter Maydell 29536106af3aSPeter Maydell if (!widenfn) { 29546106af3aSPeter Maydell return false; 29556106af3aSPeter Maydell } 29566106af3aSPeter Maydell 29576106af3aSPeter Maydell if (!vfp_access_check(s)) { 29586106af3aSPeter Maydell return true; 29596106af3aSPeter Maydell } 29606106af3aSPeter Maydell 29616106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 29626106af3aSPeter Maydell TCGv_i32 tmp; 29636106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 29646106af3aSPeter Maydell 29656106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 29666106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 29676106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 2968a712266fSRichard Henderson 2969a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 2970a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2, MO_32); 29716106af3aSPeter Maydell widenfn(rm0_64, tmp); 2972a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32); 29736106af3aSPeter Maydell widenfn(rm1_64, tmp); 2974a712266fSRichard Henderson 29756106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 29766106af3aSPeter Maydell 29776106af3aSPeter Maydell if (accfn) { 29786106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 29790aa8e700SRichard Henderson read_neon_element64(tmp64, a->vd, pass, MO_64); 29806106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 29816106af3aSPeter Maydell } 29820aa8e700SRichard Henderson write_neon_element64(rd_64, a->vd, pass, MO_64); 29836106af3aSPeter Maydell } 29846106af3aSPeter Maydell return true; 29856106af3aSPeter Maydell } 29866106af3aSPeter Maydell 29876106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 29886106af3aSPeter Maydell { 29896106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 29906106af3aSPeter Maydell gen_helper_neon_widen_s8, 29916106af3aSPeter Maydell gen_helper_neon_widen_s16, 29926106af3aSPeter Maydell tcg_gen_ext_i32_i64, 29936106af3aSPeter Maydell NULL, 29946106af3aSPeter Maydell }; 29956106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 29966106af3aSPeter Maydell gen_helper_neon_paddl_u16, 29976106af3aSPeter Maydell gen_helper_neon_paddl_u32, 29986106af3aSPeter Maydell tcg_gen_add_i64, 29996106af3aSPeter Maydell NULL, 30006106af3aSPeter Maydell }; 30016106af3aSPeter Maydell 30026106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 30036106af3aSPeter Maydell } 30046106af3aSPeter Maydell 30056106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 30066106af3aSPeter Maydell { 30076106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30086106af3aSPeter Maydell gen_helper_neon_widen_u8, 30096106af3aSPeter Maydell gen_helper_neon_widen_u16, 30106106af3aSPeter Maydell tcg_gen_extu_i32_i64, 30116106af3aSPeter Maydell NULL, 30126106af3aSPeter Maydell }; 30136106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30146106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30156106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30166106af3aSPeter Maydell tcg_gen_add_i64, 30176106af3aSPeter Maydell NULL, 30186106af3aSPeter Maydell }; 30196106af3aSPeter Maydell 30206106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 30216106af3aSPeter Maydell } 30226106af3aSPeter Maydell 30236106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 30246106af3aSPeter Maydell { 30256106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30266106af3aSPeter Maydell gen_helper_neon_widen_s8, 30276106af3aSPeter Maydell gen_helper_neon_widen_s16, 30286106af3aSPeter Maydell tcg_gen_ext_i32_i64, 30296106af3aSPeter Maydell NULL, 30306106af3aSPeter Maydell }; 30316106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30326106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30336106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30346106af3aSPeter Maydell tcg_gen_add_i64, 30356106af3aSPeter Maydell NULL, 30366106af3aSPeter Maydell }; 30376106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 30386106af3aSPeter Maydell gen_helper_neon_addl_u16, 30396106af3aSPeter Maydell gen_helper_neon_addl_u32, 30406106af3aSPeter Maydell tcg_gen_add_i64, 30416106af3aSPeter Maydell NULL, 30426106af3aSPeter Maydell }; 30436106af3aSPeter Maydell 30446106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 30456106af3aSPeter Maydell accfn[a->size]); 30466106af3aSPeter Maydell } 30476106af3aSPeter Maydell 30486106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 30496106af3aSPeter Maydell { 30506106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30516106af3aSPeter Maydell gen_helper_neon_widen_u8, 30526106af3aSPeter Maydell gen_helper_neon_widen_u16, 30536106af3aSPeter Maydell tcg_gen_extu_i32_i64, 30546106af3aSPeter Maydell NULL, 30556106af3aSPeter Maydell }; 30566106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30576106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30586106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30596106af3aSPeter Maydell tcg_gen_add_i64, 30606106af3aSPeter Maydell NULL, 30616106af3aSPeter Maydell }; 30626106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 30636106af3aSPeter Maydell gen_helper_neon_addl_u16, 30646106af3aSPeter Maydell gen_helper_neon_addl_u32, 30656106af3aSPeter Maydell tcg_gen_add_i64, 30666106af3aSPeter Maydell NULL, 30676106af3aSPeter Maydell }; 30686106af3aSPeter Maydell 30696106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 30706106af3aSPeter Maydell accfn[a->size]); 30716106af3aSPeter Maydell } 3072567663a2SPeter Maydell 3073567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3074567663a2SPeter Maydell 3075567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3076567663a2SPeter Maydell ZipFn *fn) 3077567663a2SPeter Maydell { 3078567663a2SPeter Maydell TCGv_ptr pd, pm; 3079567663a2SPeter Maydell 3080567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3081567663a2SPeter Maydell return false; 3082567663a2SPeter Maydell } 3083567663a2SPeter Maydell 3084567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3085567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3086567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3087567663a2SPeter Maydell return false; 3088567663a2SPeter Maydell } 3089567663a2SPeter Maydell 3090567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3091567663a2SPeter Maydell return false; 3092567663a2SPeter Maydell } 3093567663a2SPeter Maydell 3094567663a2SPeter Maydell if (!fn) { 3095567663a2SPeter Maydell /* Bad size or size/q combination */ 3096567663a2SPeter Maydell return false; 3097567663a2SPeter Maydell } 3098567663a2SPeter Maydell 3099567663a2SPeter Maydell if (!vfp_access_check(s)) { 3100567663a2SPeter Maydell return true; 3101567663a2SPeter Maydell } 3102567663a2SPeter Maydell 3103567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3104567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3105567663a2SPeter Maydell fn(pd, pm); 3106567663a2SPeter Maydell return true; 3107567663a2SPeter Maydell } 3108567663a2SPeter Maydell 3109567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3110567663a2SPeter Maydell { 3111567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3112567663a2SPeter Maydell { 3113567663a2SPeter Maydell gen_helper_neon_unzip8, 3114567663a2SPeter Maydell gen_helper_neon_unzip16, 3115567663a2SPeter Maydell NULL, 3116567663a2SPeter Maydell NULL, 3117567663a2SPeter Maydell }, { 3118567663a2SPeter Maydell gen_helper_neon_qunzip8, 3119567663a2SPeter Maydell gen_helper_neon_qunzip16, 3120567663a2SPeter Maydell gen_helper_neon_qunzip32, 3121567663a2SPeter Maydell NULL, 3122567663a2SPeter Maydell } 3123567663a2SPeter Maydell }; 3124567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3125567663a2SPeter Maydell } 3126567663a2SPeter Maydell 3127567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3128567663a2SPeter Maydell { 3129567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3130567663a2SPeter Maydell { 3131567663a2SPeter Maydell gen_helper_neon_zip8, 3132567663a2SPeter Maydell gen_helper_neon_zip16, 3133567663a2SPeter Maydell NULL, 3134567663a2SPeter Maydell NULL, 3135567663a2SPeter Maydell }, { 3136567663a2SPeter Maydell gen_helper_neon_qzip8, 3137567663a2SPeter Maydell gen_helper_neon_qzip16, 3138567663a2SPeter Maydell gen_helper_neon_qzip32, 3139567663a2SPeter Maydell NULL, 3140567663a2SPeter Maydell } 3141567663a2SPeter Maydell }; 3142567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3143567663a2SPeter Maydell } 31443882bdacSPeter Maydell 31453882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 31463882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 31473882bdacSPeter Maydell { 31483882bdacSPeter Maydell TCGv_i64 rm; 31493882bdacSPeter Maydell TCGv_i32 rd0, rd1; 31503882bdacSPeter Maydell 31513882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 31523882bdacSPeter Maydell return false; 31533882bdacSPeter Maydell } 31543882bdacSPeter Maydell 31553882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 31563882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 31573882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 31583882bdacSPeter Maydell return false; 31593882bdacSPeter Maydell } 31603882bdacSPeter Maydell 31613882bdacSPeter Maydell if (a->vm & 1) { 31623882bdacSPeter Maydell return false; 31633882bdacSPeter Maydell } 31643882bdacSPeter Maydell 31653882bdacSPeter Maydell if (!narrowfn) { 31663882bdacSPeter Maydell return false; 31673882bdacSPeter Maydell } 31683882bdacSPeter Maydell 31693882bdacSPeter Maydell if (!vfp_access_check(s)) { 31703882bdacSPeter Maydell return true; 31713882bdacSPeter Maydell } 31723882bdacSPeter Maydell 31733882bdacSPeter Maydell rm = tcg_temp_new_i64(); 31743882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 31753882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 31763882bdacSPeter Maydell 31770aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 0, MO_64); 31783882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 31790aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 1, MO_64); 31803882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 3181a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 3182a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 31833882bdacSPeter Maydell return true; 31843882bdacSPeter Maydell } 31853882bdacSPeter Maydell 31863882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 31873882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 31883882bdacSPeter Maydell { \ 31893882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 31903882bdacSPeter Maydell FUNC##8, \ 31913882bdacSPeter Maydell FUNC##16, \ 31923882bdacSPeter Maydell FUNC##32, \ 31933882bdacSPeter Maydell NULL, \ 31943882bdacSPeter Maydell }; \ 31953882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 31963882bdacSPeter Maydell } 31973882bdacSPeter Maydell 31983882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 31993882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 32003882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 32013882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3202749e2be3SPeter Maydell 3203749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3204749e2be3SPeter Maydell { 3205749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3206749e2be3SPeter Maydell TCGv_i64 rd; 3207749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3208749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3209749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3210749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3211749e2be3SPeter Maydell NULL, 3212749e2be3SPeter Maydell }; 3213749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3214749e2be3SPeter Maydell 3215749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3216749e2be3SPeter Maydell return false; 3217749e2be3SPeter Maydell } 3218749e2be3SPeter Maydell 3219749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3220749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3221749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3222749e2be3SPeter Maydell return false; 3223749e2be3SPeter Maydell } 3224749e2be3SPeter Maydell 3225749e2be3SPeter Maydell if (a->vd & 1) { 3226749e2be3SPeter Maydell return false; 3227749e2be3SPeter Maydell } 3228749e2be3SPeter Maydell 3229749e2be3SPeter Maydell if (!widenfn) { 3230749e2be3SPeter Maydell return false; 3231749e2be3SPeter Maydell } 3232749e2be3SPeter Maydell 3233749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3234749e2be3SPeter Maydell return true; 3235749e2be3SPeter Maydell } 3236749e2be3SPeter Maydell 3237749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3238a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 3239a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 3240749e2be3SPeter Maydell 3241a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 3242a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 3243749e2be3SPeter Maydell 3244749e2be3SPeter Maydell widenfn(rd, rm0); 3245749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 32460aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 0, MO_64); 3247749e2be3SPeter Maydell widenfn(rd, rm1); 3248749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 32490aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 1, MO_64); 3250749e2be3SPeter Maydell return true; 3251749e2be3SPeter Maydell } 3252654a5173SPeter Maydell 3253d29b17caSRichard Henderson static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a) 3254d29b17caSRichard Henderson { 3255d29b17caSRichard Henderson TCGv_ptr fpst; 3256d29b17caSRichard Henderson TCGv_i64 tmp; 3257d29b17caSRichard Henderson TCGv_i32 dst0, dst1; 3258d29b17caSRichard Henderson 3259d29b17caSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 3260d29b17caSRichard Henderson return false; 3261d29b17caSRichard Henderson } 3262d29b17caSRichard Henderson 3263d29b17caSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 3264d29b17caSRichard Henderson if (!dc_isar_feature(aa32_simd_r32, s) && 3265d29b17caSRichard Henderson ((a->vd | a->vm) & 0x10)) { 3266d29b17caSRichard Henderson return false; 3267d29b17caSRichard Henderson } 3268d29b17caSRichard Henderson 3269d29b17caSRichard Henderson if ((a->vm & 1) || (a->size != 1)) { 3270d29b17caSRichard Henderson return false; 3271d29b17caSRichard Henderson } 3272d29b17caSRichard Henderson 3273d29b17caSRichard Henderson if (!vfp_access_check(s)) { 3274d29b17caSRichard Henderson return true; 3275d29b17caSRichard Henderson } 3276d29b17caSRichard Henderson 3277d29b17caSRichard Henderson fpst = fpstatus_ptr(FPST_STD); 3278d29b17caSRichard Henderson tmp = tcg_temp_new_i64(); 3279d29b17caSRichard Henderson dst0 = tcg_temp_new_i32(); 3280d29b17caSRichard Henderson dst1 = tcg_temp_new_i32(); 3281d29b17caSRichard Henderson 3282d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 0, MO_64); 3283d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst0, tmp, fpst); 3284d29b17caSRichard Henderson 3285d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 1, MO_64); 3286d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst1, tmp, fpst); 3287d29b17caSRichard Henderson 3288d29b17caSRichard Henderson write_neon_element32(dst0, a->vd, 0, MO_32); 3289d29b17caSRichard Henderson write_neon_element32(dst1, a->vd, 1, MO_32); 3290d29b17caSRichard Henderson return true; 3291d29b17caSRichard Henderson } 3292d29b17caSRichard Henderson 3293654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3294654a5173SPeter Maydell { 3295654a5173SPeter Maydell TCGv_ptr fpst; 3296654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3297654a5173SPeter Maydell 3298654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3299654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3300654a5173SPeter Maydell return false; 3301654a5173SPeter Maydell } 3302654a5173SPeter Maydell 3303654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3304654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3305654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3306654a5173SPeter Maydell return false; 3307654a5173SPeter Maydell } 3308654a5173SPeter Maydell 3309654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3310654a5173SPeter Maydell return false; 3311654a5173SPeter Maydell } 3312654a5173SPeter Maydell 3313654a5173SPeter Maydell if (!vfp_access_check(s)) { 3314654a5173SPeter Maydell return true; 3315654a5173SPeter Maydell } 3316654a5173SPeter Maydell 3317a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3318654a5173SPeter Maydell ahp = get_ahp_flag(); 3319a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3320a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3321654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3322a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3323a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3324654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3325654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3326654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3327a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 2, MO_32); 3328654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3329a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 3330a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 3, MO_32); 3331a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 0, MO_32); 3332654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3333654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3334654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3335a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 3336654a5173SPeter Maydell return true; 3337654a5173SPeter Maydell } 3338654a5173SPeter Maydell 3339654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3340654a5173SPeter Maydell { 3341654a5173SPeter Maydell TCGv_ptr fpst; 3342654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3343654a5173SPeter Maydell 3344654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3345654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3346654a5173SPeter Maydell return false; 3347654a5173SPeter Maydell } 3348654a5173SPeter Maydell 3349654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3350654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3351654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3352654a5173SPeter Maydell return false; 3353654a5173SPeter Maydell } 3354654a5173SPeter Maydell 3355654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3356654a5173SPeter Maydell return false; 3357654a5173SPeter Maydell } 3358654a5173SPeter Maydell 3359654a5173SPeter Maydell if (!vfp_access_check(s)) { 3360654a5173SPeter Maydell return true; 3361654a5173SPeter Maydell } 3362654a5173SPeter Maydell 3363a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3364654a5173SPeter Maydell ahp = get_ahp_flag(); 3365654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3366a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3367a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3368a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3369a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3370654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3371654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3372a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 0, MO_32); 3373654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3374654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3375a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 1, MO_32); 3376654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3377654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3378a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 2, MO_32); 3379654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3380654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3381a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 3, MO_32); 3382654a5173SPeter Maydell return true; 3383654a5173SPeter Maydell } 338475153179SPeter Maydell 338575153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 338675153179SPeter Maydell { 338775153179SPeter Maydell int vec_size = a->q ? 16 : 8; 3388015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 3389015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 339075153179SPeter Maydell 339175153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 339275153179SPeter Maydell return false; 339375153179SPeter Maydell } 339475153179SPeter Maydell 339575153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 339675153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 339775153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 339875153179SPeter Maydell return false; 339975153179SPeter Maydell } 340075153179SPeter Maydell 340175153179SPeter Maydell if (a->size == 3) { 340275153179SPeter Maydell return false; 340375153179SPeter Maydell } 340475153179SPeter Maydell 340575153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 340675153179SPeter Maydell return false; 340775153179SPeter Maydell } 340875153179SPeter Maydell 340975153179SPeter Maydell if (!vfp_access_check(s)) { 341075153179SPeter Maydell return true; 341175153179SPeter Maydell } 341275153179SPeter Maydell 341375153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 341475153179SPeter Maydell 341575153179SPeter Maydell return true; 341675153179SPeter Maydell } 341775153179SPeter Maydell 341875153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 341975153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 342075153179SPeter Maydell { \ 342175153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 342275153179SPeter Maydell } 342375153179SPeter Maydell 342475153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 342575153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 342675153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 342775153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 342875153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 342975153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 343075153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 343175153179SPeter Maydell 343275153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 343375153179SPeter Maydell { 343475153179SPeter Maydell if (a->size != 0) { 343575153179SPeter Maydell return false; 343675153179SPeter Maydell } 343775153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 343875153179SPeter Maydell } 34390b30dd5bSPeter Maydell 34400b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 34410b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 34420b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 34430b30dd5bSPeter Maydell uint32_t maxsz) \ 34440b30dd5bSPeter Maydell { \ 34450b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 34460b30dd5bSPeter Maydell DATA, FUNC); \ 34470b30dd5bSPeter Maydell } 34480b30dd5bSPeter Maydell 34490b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 34500b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 34510b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 34520b30dd5bSPeter Maydell uint32_t maxsz) \ 34530b30dd5bSPeter Maydell { \ 34540b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 34550b30dd5bSPeter Maydell } 34560b30dd5bSPeter Maydell 34570b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 34580b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 34590b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 34600b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 34610b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 34620b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 34630b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 34640b30dd5bSPeter Maydell 34650b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 34660b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 34670b30dd5bSPeter Maydell { \ 34680b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 34690b30dd5bSPeter Maydell return false; \ 34700b30dd5bSPeter Maydell } \ 34710b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 34720b30dd5bSPeter Maydell } 34730b30dd5bSPeter Maydell 34740b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 34750b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 34760b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 34770b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 34780b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 34790b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 34800b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 348189668082SPeter Maydell 348289668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 348389668082SPeter Maydell { 3484a712266fSRichard Henderson TCGv_i32 tmp; 348589668082SPeter Maydell int pass; 348689668082SPeter Maydell 348789668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 348889668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 348989668082SPeter Maydell return false; 349089668082SPeter Maydell } 349189668082SPeter Maydell 349289668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 349389668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 349489668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 349589668082SPeter Maydell return false; 349689668082SPeter Maydell } 349789668082SPeter Maydell 349889668082SPeter Maydell if (!fn) { 349989668082SPeter Maydell return false; 350089668082SPeter Maydell } 350189668082SPeter Maydell 350289668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 350389668082SPeter Maydell return false; 350489668082SPeter Maydell } 350589668082SPeter Maydell 350689668082SPeter Maydell if (!vfp_access_check(s)) { 350789668082SPeter Maydell return true; 350889668082SPeter Maydell } 350989668082SPeter Maydell 3510a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 351189668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3512a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 351389668082SPeter Maydell fn(tmp, tmp); 3514a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 351589668082SPeter Maydell } 351689668082SPeter Maydell return true; 351789668082SPeter Maydell } 351889668082SPeter Maydell 351989668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 352089668082SPeter Maydell { 352189668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 352289668082SPeter Maydell tcg_gen_bswap32_i32, 352389668082SPeter Maydell gen_swap_half, 352489668082SPeter Maydell NULL, 352589668082SPeter Maydell NULL, 352689668082SPeter Maydell }; 352789668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 352889668082SPeter Maydell } 352989668082SPeter Maydell 353089668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 353189668082SPeter Maydell { 353289668082SPeter Maydell if (a->size != 0) { 353389668082SPeter Maydell return false; 353489668082SPeter Maydell } 353589668082SPeter Maydell return do_2misc(s, a, gen_rev16); 353689668082SPeter Maydell } 353784eae770SPeter Maydell 353884eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 353984eae770SPeter Maydell { 354084eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 354184eae770SPeter Maydell gen_helper_neon_cls_s8, 354284eae770SPeter Maydell gen_helper_neon_cls_s16, 354384eae770SPeter Maydell gen_helper_neon_cls_s32, 354484eae770SPeter Maydell NULL, 354584eae770SPeter Maydell }; 354684eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 354784eae770SPeter Maydell } 354884eae770SPeter Maydell 354984eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 355084eae770SPeter Maydell { 355184eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 355284eae770SPeter Maydell } 355384eae770SPeter Maydell 355484eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 355584eae770SPeter Maydell { 355684eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 355784eae770SPeter Maydell gen_helper_neon_clz_u8, 355884eae770SPeter Maydell gen_helper_neon_clz_u16, 355984eae770SPeter Maydell do_VCLZ_32, 356084eae770SPeter Maydell NULL, 356184eae770SPeter Maydell }; 356284eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 356384eae770SPeter Maydell } 356484eae770SPeter Maydell 356584eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 356684eae770SPeter Maydell { 356784eae770SPeter Maydell if (a->size != 0) { 356884eae770SPeter Maydell return false; 356984eae770SPeter Maydell } 357084eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 357184eae770SPeter Maydell } 357284eae770SPeter Maydell 35732b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 35742b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 35752b70d8cdSPeter Maydell { 35762b70d8cdSPeter Maydell tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs, 35772b70d8cdSPeter Maydell vece == MO_16 ? 0x7fff : 0x7fffffff, 35782b70d8cdSPeter Maydell oprsz, maxsz); 35792b70d8cdSPeter Maydell } 35802b70d8cdSPeter Maydell 358184eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 358284eae770SPeter Maydell { 35832b70d8cdSPeter Maydell if (a->size == MO_16) { 35842b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 358584eae770SPeter Maydell return false; 358684eae770SPeter Maydell } 35872b70d8cdSPeter Maydell } else if (a->size != MO_32) { 35882b70d8cdSPeter Maydell return false; 35892b70d8cdSPeter Maydell } 35902b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VABS_F); 35912b70d8cdSPeter Maydell } 35922b70d8cdSPeter Maydell 35932b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 35942b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 35952b70d8cdSPeter Maydell { 35962b70d8cdSPeter Maydell tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs, 35972b70d8cdSPeter Maydell vece == MO_16 ? 0x8000 : 0x80000000, 35982b70d8cdSPeter Maydell oprsz, maxsz); 359984eae770SPeter Maydell } 360084eae770SPeter Maydell 360184eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 360284eae770SPeter Maydell { 36032b70d8cdSPeter Maydell if (a->size == MO_16) { 36042b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 360584eae770SPeter Maydell return false; 360684eae770SPeter Maydell } 36072b70d8cdSPeter Maydell } else if (a->size != MO_32) { 36082b70d8cdSPeter Maydell return false; 36092b70d8cdSPeter Maydell } 36102b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VNEG_F); 361184eae770SPeter Maydell } 361284eae770SPeter Maydell 361384eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 361484eae770SPeter Maydell { 361584eae770SPeter Maydell if (a->size != 2) { 361684eae770SPeter Maydell return false; 361784eae770SPeter Maydell } 361884eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 361984eae770SPeter Maydell } 362084eae770SPeter Maydell 362184eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 362284eae770SPeter Maydell { 362384eae770SPeter Maydell if (a->size != 2) { 362484eae770SPeter Maydell return false; 362584eae770SPeter Maydell } 362684eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 362784eae770SPeter Maydell } 36284936f38aSPeter Maydell 36294936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 36304936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 36314936f38aSPeter Maydell { \ 36324936f38aSPeter Maydell FUNC(d, cpu_env, m); \ 36334936f38aSPeter Maydell } 36344936f38aSPeter Maydell 36354936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 36364936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 36374936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 36384936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 36394936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 36404936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 36414936f38aSPeter Maydell 36424936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 36434936f38aSPeter Maydell { 36444936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 36454936f38aSPeter Maydell gen_VQABS_s8, 36464936f38aSPeter Maydell gen_VQABS_s16, 36474936f38aSPeter Maydell gen_VQABS_s32, 36484936f38aSPeter Maydell NULL, 36494936f38aSPeter Maydell }; 36504936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 36514936f38aSPeter Maydell } 36524936f38aSPeter Maydell 36534936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 36544936f38aSPeter Maydell { 36554936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 36564936f38aSPeter Maydell gen_VQNEG_s8, 36574936f38aSPeter Maydell gen_VQNEG_s16, 36584936f38aSPeter Maydell gen_VQNEG_s32, 36594936f38aSPeter Maydell NULL, 36604936f38aSPeter Maydell }; 36614936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 36624936f38aSPeter Maydell } 36633e96b205SPeter Maydell 36644a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC) \ 36654a15d9a3SPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 36664a15d9a3SPeter Maydell uint32_t rm_ofs, \ 36674a15d9a3SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 36684a15d9a3SPeter Maydell { \ 36694a15d9a3SPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 36704a15d9a3SPeter Maydell NULL, HFUNC, SFUNC, NULL, \ 36714a15d9a3SPeter Maydell }; \ 36724a15d9a3SPeter Maydell TCGv_ptr fpst; \ 36734a15d9a3SPeter Maydell fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD); \ 36744a15d9a3SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0, \ 36754a15d9a3SPeter Maydell fns[vece]); \ 36764a15d9a3SPeter Maydell } \ 36774a15d9a3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 36784a15d9a3SPeter Maydell { \ 36794a15d9a3SPeter Maydell if (a->size == MO_16) { \ 36804a15d9a3SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 36814a15d9a3SPeter Maydell return false; \ 36824a15d9a3SPeter Maydell } \ 36834a15d9a3SPeter Maydell } else if (a->size != MO_32) { \ 36844a15d9a3SPeter Maydell return false; \ 36854a15d9a3SPeter Maydell } \ 36864a15d9a3SPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 36874a15d9a3SPeter Maydell } 36884a15d9a3SPeter Maydell 36894a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s) 36904a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s) 3691635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s) 3692635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s) 3693635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s) 3694635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s) 3695635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s) 36967782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos) 36977782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos) 36987782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs) 36997782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs) 37004a15d9a3SPeter Maydell 370123afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s) 370223afcdd2SPeter Maydell 37033e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 37043e96b205SPeter Maydell { 37053e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 37063e96b205SPeter Maydell return false; 37073e96b205SPeter Maydell } 370823afcdd2SPeter Maydell return trans_VRINTX_impl(s, a); 37093e96b205SPeter Maydell } 3710baa59323SPeter Maydell 3711ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP) \ 3712ca88a6efSPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 3713ca88a6efSPeter Maydell uint32_t rm_ofs, \ 3714ca88a6efSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 3715ca88a6efSPeter Maydell { \ 3716ca88a6efSPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 3717ca88a6efSPeter Maydell NULL, \ 3718ca88a6efSPeter Maydell gen_helper_gvec_##OP##h, \ 3719ca88a6efSPeter Maydell gen_helper_gvec_##OP##s, \ 3720ca88a6efSPeter Maydell NULL, \ 3721ca88a6efSPeter Maydell }; \ 3722ca88a6efSPeter Maydell TCGv_ptr fpst; \ 3723ca88a6efSPeter Maydell fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD); \ 3724ca88a6efSPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, \ 3725ca88a6efSPeter Maydell arm_rmode_to_sf(RMODE), fns[vece]); \ 3726ca88a6efSPeter Maydell } \ 3727a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3728a183d5fbSPeter Maydell { \ 3729ca88a6efSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { \ 3730ca88a6efSPeter Maydell return false; \ 3731ca88a6efSPeter Maydell } \ 3732ca88a6efSPeter Maydell if (a->size == MO_16) { \ 3733ca88a6efSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 3734ca88a6efSPeter Maydell return false; \ 3735ca88a6efSPeter Maydell } \ 3736ca88a6efSPeter Maydell } else if (a->size != MO_32) { \ 3737ca88a6efSPeter Maydell return false; \ 3738ca88a6efSPeter Maydell } \ 3739ca88a6efSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 3740a183d5fbSPeter Maydell } 3741a183d5fbSPeter Maydell 3742ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u) 3743ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s) 3744ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u) 3745ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s) 3746ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u) 3747ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s) 3748ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u) 3749ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s) 37508ab3a227SPeter Maydell 375118725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_) 375218725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_) 375318725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_) 375418725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_) 375518725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_) 375618725916SPeter Maydell 37578ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 37588ab3a227SPeter Maydell { 37598ab3a227SPeter Maydell TCGv_i64 rm, rd; 37608ab3a227SPeter Maydell int pass; 37618ab3a227SPeter Maydell 37628ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 37638ab3a227SPeter Maydell return false; 37648ab3a227SPeter Maydell } 37658ab3a227SPeter Maydell 37668ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 37678ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 37688ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 37698ab3a227SPeter Maydell return false; 37708ab3a227SPeter Maydell } 37718ab3a227SPeter Maydell 37728ab3a227SPeter Maydell if (a->size != 0) { 37738ab3a227SPeter Maydell return false; 37748ab3a227SPeter Maydell } 37758ab3a227SPeter Maydell 37768ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 37778ab3a227SPeter Maydell return false; 37788ab3a227SPeter Maydell } 37798ab3a227SPeter Maydell 37808ab3a227SPeter Maydell if (!vfp_access_check(s)) { 37818ab3a227SPeter Maydell return true; 37828ab3a227SPeter Maydell } 37838ab3a227SPeter Maydell 37848ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 37858ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 37868ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 37870aa8e700SRichard Henderson read_neon_element64(rm, a->vm, pass, MO_64); 37880aa8e700SRichard Henderson read_neon_element64(rd, a->vd, pass, MO_64); 37890aa8e700SRichard Henderson write_neon_element64(rm, a->vd, pass, MO_64); 37900aa8e700SRichard Henderson write_neon_element64(rd, a->vm, pass, MO_64); 37918ab3a227SPeter Maydell } 37928ab3a227SPeter Maydell return true; 37938ab3a227SPeter Maydell } 3794*24f4531dSRichard Henderson 3795d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 3796d4366190SPeter Maydell { 3797d4366190SPeter Maydell TCGv_i32 rd, tmp; 3798d4366190SPeter Maydell 3799d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3800d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3801d4366190SPeter Maydell 3802d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 3803d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 3804d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 3805d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3806d4366190SPeter Maydell 3807d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 3808d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 3809d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 3810d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3811d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3812d4366190SPeter Maydell } 3813d4366190SPeter Maydell 3814d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 3815d4366190SPeter Maydell { 3816d4366190SPeter Maydell TCGv_i32 rd, tmp; 3817d4366190SPeter Maydell 3818d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3819d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3820d4366190SPeter Maydell 3821d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 3822d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 3823d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3824d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 3825d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 3826d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3827d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3828d4366190SPeter Maydell } 3829d4366190SPeter Maydell 3830d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 3831d4366190SPeter Maydell { 3832d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 3833d4366190SPeter Maydell int pass; 3834d4366190SPeter Maydell 3835d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3836d4366190SPeter Maydell return false; 3837d4366190SPeter Maydell } 3838d4366190SPeter Maydell 3839d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3840d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3841d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3842d4366190SPeter Maydell return false; 3843d4366190SPeter Maydell } 3844d4366190SPeter Maydell 3845d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 3846d4366190SPeter Maydell return false; 3847d4366190SPeter Maydell } 3848d4366190SPeter Maydell 3849d4366190SPeter Maydell if (a->size == 3) { 3850d4366190SPeter Maydell return false; 3851d4366190SPeter Maydell } 3852d4366190SPeter Maydell 3853d4366190SPeter Maydell if (!vfp_access_check(s)) { 3854d4366190SPeter Maydell return true; 3855d4366190SPeter Maydell } 3856d4366190SPeter Maydell 3857a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3858a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3859a712266fSRichard Henderson if (a->size == MO_32) { 3860d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 3861a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3862a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass + 1, MO_32); 3863a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3864a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass + 1, MO_32); 3865d4366190SPeter Maydell } 3866d4366190SPeter Maydell } else { 3867d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3868a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3869a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass, MO_32); 3870a712266fSRichard Henderson if (a->size == MO_8) { 3871d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 3872d4366190SPeter Maydell } else { 3873d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 3874d4366190SPeter Maydell } 3875a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3876a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 3877d4366190SPeter Maydell } 3878d4366190SPeter Maydell } 3879d4366190SPeter Maydell return true; 3880d4366190SPeter Maydell } 38812323c5ffSRichard Henderson 38822323c5ffSRichard Henderson static bool trans_VSMMLA(DisasContext *s, arg_VSMMLA *a) 38832323c5ffSRichard Henderson { 38842323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 38852323c5ffSRichard Henderson return false; 38862323c5ffSRichard Henderson } 38872323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 38882323c5ffSRichard Henderson gen_helper_gvec_smmla_b); 38892323c5ffSRichard Henderson } 38902323c5ffSRichard Henderson 38912323c5ffSRichard Henderson static bool trans_VUMMLA(DisasContext *s, arg_VUMMLA *a) 38922323c5ffSRichard Henderson { 38932323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 38942323c5ffSRichard Henderson return false; 38952323c5ffSRichard Henderson } 38962323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 38972323c5ffSRichard Henderson gen_helper_gvec_ummla_b); 38982323c5ffSRichard Henderson } 38992323c5ffSRichard Henderson 39002323c5ffSRichard Henderson static bool trans_VUSMMLA(DisasContext *s, arg_VUSMMLA *a) 39012323c5ffSRichard Henderson { 39022323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 39032323c5ffSRichard Henderson return false; 39042323c5ffSRichard Henderson } 39052323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 39062323c5ffSRichard Henderson gen_helper_gvec_usmmla_b); 39072323c5ffSRichard Henderson } 390881266a1fSRichard Henderson 390981266a1fSRichard Henderson static bool trans_VMMLA_b16(DisasContext *s, arg_VMMLA_b16 *a) 391081266a1fSRichard Henderson { 391181266a1fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 391281266a1fSRichard Henderson return false; 391381266a1fSRichard Henderson } 391481266a1fSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 391581266a1fSRichard Henderson gen_helper_gvec_bfmmla); 391681266a1fSRichard Henderson } 39175693887fSRichard Henderson 39185693887fSRichard Henderson static bool trans_VFMA_b16(DisasContext *s, arg_VFMA_b16 *a) 39195693887fSRichard Henderson { 39205693887fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 39215693887fSRichard Henderson return false; 39225693887fSRichard Henderson } 39235693887fSRichard Henderson return do_neon_ddda_fpst(s, 7, a->vd, a->vn, a->vm, a->q, FPST_STD, 39245693887fSRichard Henderson gen_helper_gvec_bfmlal); 39255693887fSRichard Henderson } 3926458d0ab6SRichard Henderson 3927458d0ab6SRichard Henderson static bool trans_VFMA_b16_scal(DisasContext *s, arg_VFMA_b16_scal *a) 3928458d0ab6SRichard Henderson { 3929458d0ab6SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 3930458d0ab6SRichard Henderson return false; 3931458d0ab6SRichard Henderson } 3932458d0ab6SRichard Henderson return do_neon_ddda_fpst(s, 6, a->vd, a->vn, a->vm, 3933458d0ab6SRichard Henderson (a->index << 1) | a->q, FPST_STD, 3934458d0ab6SRichard Henderson gen_helper_gvec_bfmlal_idx); 3935458d0ab6SRichard Henderson } 3936