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 31123ce4e3SPeter Maydell static inline int plus1(DisasContext *s, int x) 32123ce4e3SPeter Maydell { 33123ce4e3SPeter Maydell return x + 1; 34123ce4e3SPeter Maydell } 35123ce4e3SPeter Maydell 3666432d6bSPeter Maydell static inline int rsub_64(DisasContext *s, int x) 3766432d6bSPeter Maydell { 3866432d6bSPeter Maydell return 64 - x; 3966432d6bSPeter Maydell } 4066432d6bSPeter Maydell 4166432d6bSPeter Maydell static inline int rsub_32(DisasContext *s, int x) 4266432d6bSPeter Maydell { 4366432d6bSPeter Maydell return 32 - x; 4466432d6bSPeter Maydell } 4566432d6bSPeter Maydell static inline int rsub_16(DisasContext *s, int x) 4666432d6bSPeter Maydell { 4766432d6bSPeter Maydell return 16 - x; 4866432d6bSPeter Maydell } 4966432d6bSPeter Maydell static inline int rsub_8(DisasContext *s, int x) 5066432d6bSPeter Maydell { 5166432d6bSPeter Maydell return 8 - x; 5266432d6bSPeter Maydell } 5366432d6bSPeter Maydell 546cf0f240SPeter Maydell static inline int neon_3same_fp_size(DisasContext *s, int x) 556cf0f240SPeter Maydell { 566cf0f240SPeter Maydell /* Convert 0==fp32, 1==fp16 into a MO_* value */ 576cf0f240SPeter Maydell return MO_32 - x; 586cf0f240SPeter Maydell } 596cf0f240SPeter Maydell 60625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 61139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc" 62139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc" 63139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc" 64afff8de0SPeter Maydell 65eb554d61SPeter Maydell static TCGv_ptr vfp_reg_ptr(bool dp, int reg) 66eb554d61SPeter Maydell { 67eb554d61SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 68eb554d61SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); 69eb554d61SPeter Maydell return ret; 70eb554d61SPeter Maydell } 71eb554d61SPeter Maydell 726fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) 736fb57878SPeter Maydell { 746fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 756fb57878SPeter Maydell 766fb57878SPeter Maydell switch (mop) { 776fb57878SPeter Maydell case MO_UB: 786fb57878SPeter Maydell tcg_gen_ld8u_i32(var, cpu_env, offset); 796fb57878SPeter Maydell break; 806fb57878SPeter Maydell case MO_UW: 816fb57878SPeter Maydell tcg_gen_ld16u_i32(var, cpu_env, offset); 826fb57878SPeter Maydell break; 836fb57878SPeter Maydell case MO_UL: 846fb57878SPeter Maydell tcg_gen_ld_i32(var, cpu_env, offset); 856fb57878SPeter Maydell break; 866fb57878SPeter Maydell default: 876fb57878SPeter Maydell g_assert_not_reached(); 886fb57878SPeter Maydell } 896fb57878SPeter Maydell } 906fb57878SPeter Maydell 916fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) 926fb57878SPeter Maydell { 936fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 946fb57878SPeter Maydell 956fb57878SPeter Maydell switch (mop) { 966fb57878SPeter Maydell case MO_UB: 976fb57878SPeter Maydell tcg_gen_ld8u_i64(var, cpu_env, offset); 986fb57878SPeter Maydell break; 996fb57878SPeter Maydell case MO_UW: 1006fb57878SPeter Maydell tcg_gen_ld16u_i64(var, cpu_env, offset); 1016fb57878SPeter Maydell break; 1026fb57878SPeter Maydell case MO_UL: 1036fb57878SPeter Maydell tcg_gen_ld32u_i64(var, cpu_env, offset); 1046fb57878SPeter Maydell break; 1056fb57878SPeter Maydell case MO_Q: 1066fb57878SPeter Maydell tcg_gen_ld_i64(var, cpu_env, offset); 1076fb57878SPeter Maydell break; 1086fb57878SPeter Maydell default: 1096fb57878SPeter Maydell g_assert_not_reached(); 1106fb57878SPeter Maydell } 1116fb57878SPeter Maydell } 1126fb57878SPeter Maydell 1136fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) 1146fb57878SPeter Maydell { 1156fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1166fb57878SPeter Maydell 1176fb57878SPeter Maydell switch (size) { 1186fb57878SPeter Maydell case MO_8: 1196fb57878SPeter Maydell tcg_gen_st8_i32(var, cpu_env, offset); 1206fb57878SPeter Maydell break; 1216fb57878SPeter Maydell case MO_16: 1226fb57878SPeter Maydell tcg_gen_st16_i32(var, cpu_env, offset); 1236fb57878SPeter Maydell break; 1246fb57878SPeter Maydell case MO_32: 1256fb57878SPeter Maydell tcg_gen_st_i32(var, cpu_env, offset); 1266fb57878SPeter Maydell break; 1276fb57878SPeter Maydell default: 1286fb57878SPeter Maydell g_assert_not_reached(); 1296fb57878SPeter Maydell } 1306fb57878SPeter Maydell } 1316fb57878SPeter Maydell 1326fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) 1336fb57878SPeter Maydell { 1346fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1356fb57878SPeter Maydell 1366fb57878SPeter Maydell switch (size) { 1376fb57878SPeter Maydell case MO_8: 1386fb57878SPeter Maydell tcg_gen_st8_i64(var, cpu_env, offset); 1396fb57878SPeter Maydell break; 1406fb57878SPeter Maydell case MO_16: 1416fb57878SPeter Maydell tcg_gen_st16_i64(var, cpu_env, offset); 1426fb57878SPeter Maydell break; 1436fb57878SPeter Maydell case MO_32: 1446fb57878SPeter Maydell tcg_gen_st32_i64(var, cpu_env, offset); 1456fb57878SPeter Maydell break; 1466fb57878SPeter Maydell case MO_64: 1476fb57878SPeter Maydell tcg_gen_st_i64(var, cpu_env, offset); 1486fb57878SPeter Maydell break; 1496fb57878SPeter Maydell default: 1506fb57878SPeter Maydell g_assert_not_reached(); 1516fb57878SPeter Maydell } 1526fb57878SPeter Maydell } 1536fb57878SPeter Maydell 1545a46304cSRichard Henderson static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm, 1555a46304cSRichard Henderson int data, gen_helper_gvec_4 *fn_gvec) 1565a46304cSRichard Henderson { 1575a46304cSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 1585a46304cSRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 1595a46304cSRichard Henderson return false; 1605a46304cSRichard Henderson } 1615a46304cSRichard Henderson 1625a46304cSRichard Henderson /* 1635a46304cSRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 1645a46304cSRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 1655a46304cSRichard Henderson * when we have mixed Q- and D-reg inputs. 1665a46304cSRichard Henderson */ 1675a46304cSRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 1685a46304cSRichard Henderson return false; 1695a46304cSRichard Henderson } 1705a46304cSRichard Henderson 1715a46304cSRichard Henderson if (!vfp_access_check(s)) { 1725a46304cSRichard Henderson return true; 1735a46304cSRichard Henderson } 1745a46304cSRichard Henderson 1755a46304cSRichard Henderson int opr_sz = q ? 16 : 8; 1765a46304cSRichard Henderson tcg_gen_gvec_4_ool(vfp_reg_offset(1, vd), 1775a46304cSRichard Henderson vfp_reg_offset(1, vn), 1785a46304cSRichard Henderson vfp_reg_offset(1, vm), 1795a46304cSRichard Henderson vfp_reg_offset(1, vd), 1805a46304cSRichard Henderson opr_sz, opr_sz, data, fn_gvec); 1815a46304cSRichard Henderson return true; 1825a46304cSRichard Henderson } 1835a46304cSRichard Henderson 184505fce50SRichard Henderson static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, 185505fce50SRichard Henderson int data, ARMFPStatusFlavour fp_flavour, 186505fce50SRichard Henderson gen_helper_gvec_4_ptr *fn_gvec_ptr) 187afff8de0SPeter Maydell { 188afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 189505fce50SRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 190afff8de0SPeter Maydell return false; 191afff8de0SPeter Maydell } 192afff8de0SPeter Maydell 193505fce50SRichard Henderson /* 194505fce50SRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 195505fce50SRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 196505fce50SRichard Henderson * when we have mixed Q- and D-reg inputs. 197505fce50SRichard Henderson */ 198505fce50SRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 199afff8de0SPeter Maydell return false; 200afff8de0SPeter Maydell } 201afff8de0SPeter Maydell 202afff8de0SPeter Maydell if (!vfp_access_check(s)) { 203afff8de0SPeter Maydell return true; 204afff8de0SPeter Maydell } 205afff8de0SPeter Maydell 206505fce50SRichard Henderson int opr_sz = q ? 16 : 8; 207505fce50SRichard Henderson TCGv_ptr fpst = fpstatus_ptr(fp_flavour); 208505fce50SRichard Henderson 209505fce50SRichard Henderson tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd), 210505fce50SRichard Henderson vfp_reg_offset(1, vn), 211505fce50SRichard Henderson vfp_reg_offset(1, vm), 212505fce50SRichard Henderson vfp_reg_offset(1, vd), 213505fce50SRichard Henderson fpst, opr_sz, opr_sz, data, fn_gvec_ptr); 214afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 215afff8de0SPeter Maydell return true; 216afff8de0SPeter Maydell } 21794d5eb7bSPeter Maydell 218505fce50SRichard Henderson static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 219505fce50SRichard Henderson { 220505fce50SRichard Henderson if (!dc_isar_feature(aa32_vcma, s)) { 221505fce50SRichard Henderson return false; 222505fce50SRichard Henderson } 223505fce50SRichard Henderson if (a->size == MO_16) { 224505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 225505fce50SRichard Henderson return false; 226505fce50SRichard Henderson } 227505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 228505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah); 229505fce50SRichard Henderson } 230505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 231505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas); 232505fce50SRichard Henderson } 233505fce50SRichard Henderson 23494d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 23594d5eb7bSPeter Maydell { 23694d5eb7bSPeter Maydell int opr_sz; 23794d5eb7bSPeter Maydell TCGv_ptr fpst; 23894d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 23994d5eb7bSPeter Maydell 24094d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 241d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 24294d5eb7bSPeter Maydell return false; 24394d5eb7bSPeter Maydell } 24494d5eb7bSPeter Maydell 24594d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 24694d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 24794d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 24894d5eb7bSPeter Maydell return false; 24994d5eb7bSPeter Maydell } 25094d5eb7bSPeter Maydell 25194d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 25294d5eb7bSPeter Maydell return false; 25394d5eb7bSPeter Maydell } 25494d5eb7bSPeter Maydell 25594d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 25694d5eb7bSPeter Maydell return true; 25794d5eb7bSPeter Maydell } 25894d5eb7bSPeter Maydell 25994d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 260d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 261d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 262d186a485SPeter Maydell gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds; 26394d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 26494d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 26594d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 26694d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 26794d5eb7bSPeter Maydell fn_gvec_ptr); 26894d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 26994d5eb7bSPeter Maydell return true; 27094d5eb7bSPeter Maydell } 27132da0e33SPeter Maydell 272f0ad96cbSRichard Henderson static bool trans_VSDOT(DisasContext *s, arg_VSDOT *a) 27332da0e33SPeter Maydell { 27432da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 27532da0e33SPeter Maydell return false; 27632da0e33SPeter Maydell } 2775a46304cSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 278f0ad96cbSRichard Henderson gen_helper_gvec_sdot_b); 279f0ad96cbSRichard Henderson } 280f0ad96cbSRichard Henderson 281f0ad96cbSRichard Henderson static bool trans_VUDOT(DisasContext *s, arg_VUDOT *a) 282f0ad96cbSRichard Henderson { 283f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 284f0ad96cbSRichard Henderson return false; 285f0ad96cbSRichard Henderson } 286f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 287f0ad96cbSRichard Henderson gen_helper_gvec_udot_b); 28832da0e33SPeter Maydell } 2899a107e7bSPeter Maydell 290*51879c67SRichard Henderson static bool trans_VUSDOT(DisasContext *s, arg_VUSDOT *a) 291*51879c67SRichard Henderson { 292*51879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 293*51879c67SRichard Henderson return false; 294*51879c67SRichard Henderson } 295*51879c67SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 296*51879c67SRichard Henderson gen_helper_gvec_usdot_b); 297*51879c67SRichard Henderson } 298*51879c67SRichard Henderson 2999a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 3009a107e7bSPeter Maydell { 3019a107e7bSPeter Maydell int opr_sz; 3029a107e7bSPeter Maydell 3039a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 3049a107e7bSPeter Maydell return false; 3059a107e7bSPeter Maydell } 3069a107e7bSPeter Maydell 3079a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3089a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3099a107e7bSPeter Maydell (a->vd & 0x10)) { 3109a107e7bSPeter Maydell return false; 3119a107e7bSPeter Maydell } 3129a107e7bSPeter Maydell 3139a107e7bSPeter Maydell if (a->vd & a->q) { 3149a107e7bSPeter Maydell return false; 3159a107e7bSPeter Maydell } 3169a107e7bSPeter Maydell 3179a107e7bSPeter Maydell if (!vfp_access_check(s)) { 3189a107e7bSPeter Maydell return true; 3199a107e7bSPeter Maydell } 3209a107e7bSPeter Maydell 3219a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 3229a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 3239a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 3249a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 3259a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 3269a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 3279a107e7bSPeter Maydell return true; 3289a107e7bSPeter Maydell } 3297e1b5d61SPeter Maydell 3307e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 3317e1b5d61SPeter Maydell { 332505fce50SRichard Henderson int data = (a->index << 2) | a->rot; 3337e1b5d61SPeter Maydell 3347e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 3357e1b5d61SPeter Maydell return false; 3367e1b5d61SPeter Maydell } 337505fce50SRichard Henderson if (a->size == MO_16) { 338505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 3397e1b5d61SPeter Maydell return false; 3407e1b5d61SPeter Maydell } 341505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 342505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah_idx); 3437e1b5d61SPeter Maydell } 344505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 345505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas_idx); 3467e1b5d61SPeter Maydell } 34735f5d4d1SPeter Maydell 348f0ad96cbSRichard Henderson static bool trans_VSDOT_scalar(DisasContext *s, arg_VSDOT_scalar *a) 34935f5d4d1SPeter Maydell { 35035f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 35135f5d4d1SPeter Maydell return false; 35235f5d4d1SPeter Maydell } 3535a46304cSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 354f0ad96cbSRichard Henderson gen_helper_gvec_sdot_idx_b); 355f0ad96cbSRichard Henderson } 356f0ad96cbSRichard Henderson 357f0ad96cbSRichard Henderson static bool trans_VUDOT_scalar(DisasContext *s, arg_VUDOT_scalar *a) 358f0ad96cbSRichard Henderson { 359f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 360f0ad96cbSRichard Henderson return false; 361f0ad96cbSRichard Henderson } 362f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 363f0ad96cbSRichard Henderson gen_helper_gvec_udot_idx_b); 36435f5d4d1SPeter Maydell } 365d27e82f7SPeter Maydell 366*51879c67SRichard Henderson static bool trans_VUSDOT_scalar(DisasContext *s, arg_VUSDOT_scalar *a) 367*51879c67SRichard Henderson { 368*51879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 369*51879c67SRichard Henderson return false; 370*51879c67SRichard Henderson } 371*51879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 372*51879c67SRichard Henderson gen_helper_gvec_usdot_idx_b); 373*51879c67SRichard Henderson } 374*51879c67SRichard Henderson 375*51879c67SRichard Henderson static bool trans_VSUDOT_scalar(DisasContext *s, arg_VSUDOT_scalar *a) 376*51879c67SRichard Henderson { 377*51879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 378*51879c67SRichard Henderson return false; 379*51879c67SRichard Henderson } 380*51879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 381*51879c67SRichard Henderson gen_helper_gvec_sudot_idx_b); 382*51879c67SRichard Henderson } 383*51879c67SRichard Henderson 384d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 385d27e82f7SPeter Maydell { 386d27e82f7SPeter Maydell int opr_sz; 387d27e82f7SPeter Maydell 388d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 389d27e82f7SPeter Maydell return false; 390d27e82f7SPeter Maydell } 391d27e82f7SPeter Maydell 392d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 393d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 394d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 395d27e82f7SPeter Maydell return false; 396d27e82f7SPeter Maydell } 397d27e82f7SPeter Maydell 398d27e82f7SPeter Maydell if (a->vd & a->q) { 399d27e82f7SPeter Maydell return false; 400d27e82f7SPeter Maydell } 401d27e82f7SPeter Maydell 402d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 403d27e82f7SPeter Maydell return true; 404d27e82f7SPeter Maydell } 405d27e82f7SPeter Maydell 406d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 407d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 408d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 409d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 410d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 411d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 412d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 413d27e82f7SPeter Maydell return true; 414d27e82f7SPeter Maydell } 415a27b4630SPeter Maydell 416a27b4630SPeter Maydell static struct { 417a27b4630SPeter Maydell int nregs; 418a27b4630SPeter Maydell int interleave; 419a27b4630SPeter Maydell int spacing; 420a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 421a27b4630SPeter Maydell {1, 4, 1}, 422a27b4630SPeter Maydell {1, 4, 2}, 423a27b4630SPeter Maydell {4, 1, 1}, 424a27b4630SPeter Maydell {2, 2, 2}, 425a27b4630SPeter Maydell {1, 3, 1}, 426a27b4630SPeter Maydell {1, 3, 2}, 427a27b4630SPeter Maydell {3, 1, 1}, 428a27b4630SPeter Maydell {1, 1, 1}, 429a27b4630SPeter Maydell {1, 2, 1}, 430a27b4630SPeter Maydell {1, 2, 2}, 431a27b4630SPeter Maydell {2, 1, 1} 432a27b4630SPeter Maydell }; 433a27b4630SPeter Maydell 434a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 435a27b4630SPeter Maydell int stride) 436a27b4630SPeter Maydell { 437a27b4630SPeter Maydell if (rm != 15) { 438a27b4630SPeter Maydell TCGv_i32 base; 439a27b4630SPeter Maydell 440a27b4630SPeter Maydell base = load_reg(s, rn); 441a27b4630SPeter Maydell if (rm == 13) { 442a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 443a27b4630SPeter Maydell } else { 444a27b4630SPeter Maydell TCGv_i32 index; 445a27b4630SPeter Maydell index = load_reg(s, rm); 446a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 447a27b4630SPeter Maydell tcg_temp_free_i32(index); 448a27b4630SPeter Maydell } 449a27b4630SPeter Maydell store_reg(s, rn, base); 450a27b4630SPeter Maydell } 451a27b4630SPeter Maydell } 452a27b4630SPeter Maydell 453a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 454a27b4630SPeter Maydell { 455a27b4630SPeter Maydell /* Neon load/store multiple structures */ 456a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 4577c68c196SRichard Henderson MemOp mop, align, endian; 458a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 459a27b4630SPeter Maydell int size = a->size; 460a27b4630SPeter Maydell TCGv_i64 tmp64; 461a27b4630SPeter Maydell TCGv_i32 addr, tmp; 462a27b4630SPeter Maydell 463a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 464a27b4630SPeter Maydell return false; 465a27b4630SPeter Maydell } 466a27b4630SPeter Maydell 467a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 468a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 469a27b4630SPeter Maydell return false; 470a27b4630SPeter Maydell } 471a27b4630SPeter Maydell if (a->itype > 10) { 472a27b4630SPeter Maydell return false; 473a27b4630SPeter Maydell } 474a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 475a27b4630SPeter Maydell switch (a->itype & 0xc) { 476a27b4630SPeter Maydell case 4: 477a27b4630SPeter Maydell if (a->align >= 2) { 478a27b4630SPeter Maydell return false; 479a27b4630SPeter Maydell } 480a27b4630SPeter Maydell break; 481a27b4630SPeter Maydell case 8: 482a27b4630SPeter Maydell if (a->align == 3) { 483a27b4630SPeter Maydell return false; 484a27b4630SPeter Maydell } 485a27b4630SPeter Maydell break; 486a27b4630SPeter Maydell default: 487a27b4630SPeter Maydell break; 488a27b4630SPeter Maydell } 489a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 490a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 491a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 492a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 493a27b4630SPeter Maydell return false; 494a27b4630SPeter Maydell } 495a27b4630SPeter Maydell 496a27b4630SPeter Maydell if (!vfp_access_check(s)) { 497a27b4630SPeter Maydell return true; 498a27b4630SPeter Maydell } 499a27b4630SPeter Maydell 500a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 5017c68c196SRichard Henderson endian = s->be_data; 502a27b4630SPeter Maydell if (size == 0) { 503a27b4630SPeter Maydell endian = MO_LE; 504a27b4630SPeter Maydell } 5057c68c196SRichard Henderson 5067c68c196SRichard Henderson /* Enforce alignment requested by the instruction */ 5077c68c196SRichard Henderson if (a->align) { 5087c68c196SRichard Henderson align = pow2_align(a->align + 2); /* 4 ** a->align */ 5097c68c196SRichard Henderson } else { 5107c68c196SRichard Henderson align = s->align_mem ? MO_ALIGN : 0; 5117c68c196SRichard Henderson } 5127c68c196SRichard Henderson 513a27b4630SPeter Maydell /* 514a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 515a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 516a27b4630SPeter Maydell */ 517a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 5187c68c196SRichard Henderson /* Retain any natural alignment. */ 5197c68c196SRichard Henderson if (align == MO_ALIGN) { 5207c68c196SRichard Henderson align = pow2_align(size); 5217c68c196SRichard Henderson } 522a27b4630SPeter Maydell size = 3; 523a27b4630SPeter Maydell } 5247c68c196SRichard Henderson 525a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 526a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 527a27b4630SPeter Maydell tmp = tcg_const_i32(1 << size); 528a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 5297c68c196SRichard Henderson 5307c68c196SRichard Henderson mop = endian | size | align; 531a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 532a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 533a27b4630SPeter Maydell int xs; 534a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 535a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 536a27b4630SPeter Maydell 537a27b4630SPeter Maydell if (a->l) { 5387c68c196SRichard Henderson gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop); 539a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 540a27b4630SPeter Maydell } else { 541a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 5427c68c196SRichard Henderson gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); 543a27b4630SPeter Maydell } 544a27b4630SPeter Maydell tcg_gen_add_i32(addr, addr, tmp); 5457c68c196SRichard Henderson 5467c68c196SRichard Henderson /* Subsequent memory operations inherit alignment */ 5477c68c196SRichard Henderson mop &= ~MO_AMASK; 548a27b4630SPeter Maydell } 549a27b4630SPeter Maydell } 550a27b4630SPeter Maydell } 551a27b4630SPeter Maydell tcg_temp_free_i32(addr); 552a27b4630SPeter Maydell tcg_temp_free_i32(tmp); 553a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 554a27b4630SPeter Maydell 555a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 556a27b4630SPeter Maydell return true; 557a27b4630SPeter Maydell } 5583698747cSPeter Maydell 5593698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5603698747cSPeter Maydell { 5613698747cSPeter Maydell /* Neon load single structure to all lanes */ 5623698747cSPeter Maydell int reg, stride, vec_size; 5633698747cSPeter Maydell int vd = a->vd; 5643698747cSPeter Maydell int size = a->size; 5653698747cSPeter Maydell int nregs = a->n + 1; 5663698747cSPeter Maydell TCGv_i32 addr, tmp; 567a8502b37SRichard Henderson MemOp mop, align; 5683698747cSPeter Maydell 5693698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5703698747cSPeter Maydell return false; 5713698747cSPeter Maydell } 5723698747cSPeter Maydell 5733698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5743698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5753698747cSPeter Maydell return false; 5763698747cSPeter Maydell } 5773698747cSPeter Maydell 578a8502b37SRichard Henderson align = 0; 5793698747cSPeter Maydell if (size == 3) { 5803698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5813698747cSPeter Maydell return false; 5823698747cSPeter Maydell } 5833698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 584a8502b37SRichard Henderson size = MO_32; 585a8502b37SRichard Henderson align = MO_ALIGN_16; 586a8502b37SRichard Henderson } else if (a->a) { 587a8502b37SRichard Henderson switch (nregs) { 588a8502b37SRichard Henderson case 1: 589a8502b37SRichard Henderson if (size == 0) { 5903698747cSPeter Maydell return false; 5913698747cSPeter Maydell } 592a8502b37SRichard Henderson align = MO_ALIGN; 593a8502b37SRichard Henderson break; 594a8502b37SRichard Henderson case 2: 595a8502b37SRichard Henderson align = pow2_align(size + 1); 596a8502b37SRichard Henderson break; 597a8502b37SRichard Henderson case 3: 5983698747cSPeter Maydell return false; 599a8502b37SRichard Henderson case 4: 600a8502b37SRichard Henderson align = pow2_align(size + 2); 601a8502b37SRichard Henderson break; 602a8502b37SRichard Henderson default: 603a8502b37SRichard Henderson g_assert_not_reached(); 604a8502b37SRichard Henderson } 6053698747cSPeter Maydell } 6063698747cSPeter Maydell 6073698747cSPeter Maydell if (!vfp_access_check(s)) { 6083698747cSPeter Maydell return true; 6093698747cSPeter Maydell } 6103698747cSPeter Maydell 6113698747cSPeter Maydell /* 6123698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 6133698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 6143698747cSPeter Maydell */ 6153698747cSPeter Maydell stride = a->t ? 2 : 1; 6163698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 617a8502b37SRichard Henderson mop = size | align; 6183698747cSPeter Maydell tmp = tcg_temp_new_i32(); 6193698747cSPeter Maydell addr = tcg_temp_new_i32(); 6203698747cSPeter Maydell load_reg_var(s, addr, a->rn); 6213698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 622a8502b37SRichard Henderson gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); 6233698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 6243698747cSPeter Maydell /* 6253698747cSPeter Maydell * We cannot write 16 bytes at once because the 6263698747cSPeter Maydell * destination is unaligned. 6273698747cSPeter Maydell */ 628015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6293698747cSPeter Maydell 8, 8, tmp); 630015ee81aSRichard Henderson tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1), 631015ee81aSRichard Henderson neon_full_reg_offset(vd), 8, 8); 6323698747cSPeter Maydell } else { 633015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6343698747cSPeter Maydell vec_size, vec_size, tmp); 6353698747cSPeter Maydell } 6363698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 6373698747cSPeter Maydell vd += stride; 638a8502b37SRichard Henderson 639a8502b37SRichard Henderson /* Subsequent memory operations inherit alignment */ 640a8502b37SRichard Henderson mop &= ~MO_AMASK; 6413698747cSPeter Maydell } 6423698747cSPeter Maydell tcg_temp_free_i32(tmp); 6433698747cSPeter Maydell tcg_temp_free_i32(addr); 6443698747cSPeter Maydell 6453698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 6463698747cSPeter Maydell 6473698747cSPeter Maydell return true; 6483698747cSPeter Maydell } 649123ce4e3SPeter Maydell 650123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 651123ce4e3SPeter Maydell { 652123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 653123ce4e3SPeter Maydell int reg; 654123ce4e3SPeter Maydell int nregs = a->n + 1; 655123ce4e3SPeter Maydell int vd = a->vd; 656123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 65788976ff0SRichard Henderson MemOp mop; 658123ce4e3SPeter Maydell 659123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 660123ce4e3SPeter Maydell return false; 661123ce4e3SPeter Maydell } 662123ce4e3SPeter Maydell 663123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 664123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 665123ce4e3SPeter Maydell return false; 666123ce4e3SPeter Maydell } 667123ce4e3SPeter Maydell 668123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 669123ce4e3SPeter Maydell switch (nregs) { 670123ce4e3SPeter Maydell case 1: 671123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 672a736cbc3SRichard Henderson (a->size == 2 && (a->align == 1 || a->align == 2))) { 673123ce4e3SPeter Maydell return false; 674123ce4e3SPeter Maydell } 675123ce4e3SPeter Maydell break; 676123ce4e3SPeter Maydell case 3: 677123ce4e3SPeter Maydell if ((a->align & 1) != 0) { 678123ce4e3SPeter Maydell return false; 679123ce4e3SPeter Maydell } 680123ce4e3SPeter Maydell /* fall through */ 681123ce4e3SPeter Maydell case 2: 682123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 683123ce4e3SPeter Maydell return false; 684123ce4e3SPeter Maydell } 685123ce4e3SPeter Maydell break; 686123ce4e3SPeter Maydell case 4: 687a736cbc3SRichard Henderson if (a->size == 2 && a->align == 3) { 688123ce4e3SPeter Maydell return false; 689123ce4e3SPeter Maydell } 690123ce4e3SPeter Maydell break; 691123ce4e3SPeter Maydell default: 692123ce4e3SPeter Maydell abort(); 693123ce4e3SPeter Maydell } 694123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 695123ce4e3SPeter Maydell /* 696123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 697123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 698123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 699123ce4e3SPeter Maydell */ 700123ce4e3SPeter Maydell return false; 701123ce4e3SPeter Maydell } 702123ce4e3SPeter Maydell 703123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 704123ce4e3SPeter Maydell return true; 705123ce4e3SPeter Maydell } 706123ce4e3SPeter Maydell 70788976ff0SRichard Henderson /* Pick up SCTLR settings */ 70888976ff0SRichard Henderson mop = finalize_memop(s, a->size); 70988976ff0SRichard Henderson 71088976ff0SRichard Henderson if (a->align) { 71188976ff0SRichard Henderson MemOp align_op; 71288976ff0SRichard Henderson 71388976ff0SRichard Henderson switch (nregs) { 71488976ff0SRichard Henderson case 1: 71588976ff0SRichard Henderson /* For VLD1, use natural alignment. */ 71688976ff0SRichard Henderson align_op = MO_ALIGN; 71788976ff0SRichard Henderson break; 71888976ff0SRichard Henderson case 2: 71988976ff0SRichard Henderson /* For VLD2, use double alignment. */ 72088976ff0SRichard Henderson align_op = pow2_align(a->size + 1); 72188976ff0SRichard Henderson break; 72288976ff0SRichard Henderson case 4: 72388976ff0SRichard Henderson if (a->size == MO_32) { 72488976ff0SRichard Henderson /* 72588976ff0SRichard Henderson * For VLD4.32, align = 1 is double alignment, align = 2 is 72688976ff0SRichard Henderson * quad alignment; align = 3 is rejected above. 72788976ff0SRichard Henderson */ 72888976ff0SRichard Henderson align_op = pow2_align(a->size + a->align); 72988976ff0SRichard Henderson } else { 73088976ff0SRichard Henderson /* For VLD4.8 and VLD.16, we want quad alignment. */ 73188976ff0SRichard Henderson align_op = pow2_align(a->size + 2); 73288976ff0SRichard Henderson } 73388976ff0SRichard Henderson break; 73488976ff0SRichard Henderson default: 73588976ff0SRichard Henderson /* For VLD3, the alignment field is zero and rejected above. */ 73688976ff0SRichard Henderson g_assert_not_reached(); 73788976ff0SRichard Henderson } 73888976ff0SRichard Henderson 73988976ff0SRichard Henderson mop = (mop & ~MO_AMASK) | align_op; 74088976ff0SRichard Henderson } 74188976ff0SRichard Henderson 742123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 743123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 744123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 74588976ff0SRichard Henderson 746123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 747123ce4e3SPeter Maydell if (a->l) { 74888976ff0SRichard Henderson gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop); 749123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 750123ce4e3SPeter Maydell } else { /* Store */ 751123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 75288976ff0SRichard Henderson gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop); 753123ce4e3SPeter Maydell } 754123ce4e3SPeter Maydell vd += a->stride; 755123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 75688976ff0SRichard Henderson 75788976ff0SRichard Henderson /* Subsequent memory operations inherit alignment */ 75888976ff0SRichard Henderson mop &= ~MO_AMASK; 759123ce4e3SPeter Maydell } 760123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 761123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 762123ce4e3SPeter Maydell 763123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 764123ce4e3SPeter Maydell 765123ce4e3SPeter Maydell return true; 766123ce4e3SPeter Maydell } 767a4e143acSPeter Maydell 768a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 769a4e143acSPeter Maydell { 770a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 771015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 772015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 773015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 774a4e143acSPeter Maydell 775a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 776a4e143acSPeter Maydell return false; 777a4e143acSPeter Maydell } 778a4e143acSPeter Maydell 779a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 780a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 781a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 782a4e143acSPeter Maydell return false; 783a4e143acSPeter Maydell } 784a4e143acSPeter Maydell 785a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 786a4e143acSPeter Maydell return false; 787a4e143acSPeter Maydell } 788a4e143acSPeter Maydell 789a4e143acSPeter Maydell if (!vfp_access_check(s)) { 790a4e143acSPeter Maydell return true; 791a4e143acSPeter Maydell } 792a4e143acSPeter Maydell 793a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 794a4e143acSPeter Maydell return true; 795a4e143acSPeter Maydell } 796a4e143acSPeter Maydell 797a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 798a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 799a4e143acSPeter Maydell { \ 800a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 801a4e143acSPeter Maydell } 802a4e143acSPeter Maydell 803a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 804a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 80535a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 80635a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 80735a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 80835a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 80935a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 8108161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 8118161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 812c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 813c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 814c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 815c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 81635a548edSPeter Maydell 81735a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 81835a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 81935a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 82035a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 82135a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 82235a548edSPeter Maydell { \ 82335a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 82435a548edSPeter Maydell } \ 82535a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 82635a548edSPeter Maydell 82735a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 82835a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 82935a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 83036b59310SPeter Maydell 83136b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 83236b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 83336b59310SPeter Maydell { \ 83436b59310SPeter Maydell if (a->size == 3) { \ 83536b59310SPeter Maydell return false; \ 83636b59310SPeter Maydell } \ 83736b59310SPeter Maydell return do_3same(s, a, FUNC); \ 83836b59310SPeter Maydell } 83936b59310SPeter Maydell 84036b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 84136b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 84236b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 84336b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 8440de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 84527106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 84627106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 8478161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 8487715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 8497715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 8507715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 8517715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 85202bd0cdbSPeter Maydell 85302bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 85402bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 85502bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 85602bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 85702bd0cdbSPeter Maydell { \ 85802bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 85902bd0cdbSPeter Maydell } \ 86002bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 86102bd0cdbSPeter Maydell 86202bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 86302bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 86402bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 86502bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 86602bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 86702bd0cdbSPeter Maydell 868effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 869effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 870effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 871effa992fSRichard Henderson { \ 872effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 8730de34fd4SPeter Maydell } 8740de34fd4SPeter Maydell 875effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 876effa992fSRichard Henderson 8770de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 8780de34fd4SPeter Maydell { 8790de34fd4SPeter Maydell if (a->size != 0) { 8800de34fd4SPeter Maydell return false; 8810de34fd4SPeter Maydell } 8820de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 8830de34fd4SPeter Maydell } 884a0635695SPeter Maydell 885a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 886a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 887a0635695SPeter Maydell { \ 888a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 889a0635695SPeter Maydell return false; \ 890a0635695SPeter Maydell } \ 891a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 892a0635695SPeter Maydell return false; \ 893a0635695SPeter Maydell } \ 894a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 895a0635695SPeter Maydell } 896a0635695SPeter Maydell 897a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 898a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 89921290edfSPeter Maydell 900afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 901afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 902afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 903afc8b7d3SRichard Henderson { \ 904afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 905afc8b7d3SRichard Henderson return false; \ 906afc8b7d3SRichard Henderson } \ 907afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 90821290edfSPeter Maydell } 90921290edfSPeter Maydell 910afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 911afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 912afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 913afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 91421290edfSPeter Maydell 915effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 916effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 917effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 918effa992fSRichard Henderson { \ 919effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 920effa992fSRichard Henderson return false; \ 921effa992fSRichard Henderson } \ 922effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 92321290edfSPeter Maydell } 92421290edfSPeter Maydell 925effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 926effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 927effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 92835d4352fSPeter Maydell 92935d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 93035d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 93135d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 93235d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 93335d4352fSPeter Maydell { \ 93435d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 93535d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 93635d4352fSPeter Maydell } \ 93735d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 93835d4352fSPeter Maydell 93935d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 94035d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 94135d4352fSPeter Maydell { \ 94235d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 94335d4352fSPeter Maydell } \ 94435d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 94535d4352fSPeter Maydell 94635d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 94735d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 94835d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 94935d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 95035d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 95135d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 952cb294bcaSPeter Maydell 953cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 954cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 955cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 956cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 957cb294bcaSPeter Maydell { \ 958cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 959cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 960cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 961cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 962cb294bcaSPeter Maydell { 0 }, \ 963cb294bcaSPeter Maydell }; \ 964cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 965cb294bcaSPeter Maydell } \ 966cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 967cb294bcaSPeter Maydell { \ 968cb294bcaSPeter Maydell if (a->size > 2) { \ 969cb294bcaSPeter Maydell return false; \ 970cb294bcaSPeter Maydell } \ 971cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 972cb294bcaSPeter Maydell } 973cb294bcaSPeter Maydell 9746812dfdcSPeter Maydell /* 9756812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 9766812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 9776812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 9786812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 9796812dfdcSPeter Maydell */ 9806812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 9816812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 9826812dfdcSPeter Maydell { \ 9836812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 9846812dfdcSPeter Maydell } 9856812dfdcSPeter Maydell 9866812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 9876812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 9886812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 9896812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 9906812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9916812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9926812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9936812dfdcSPeter Maydell { \ 9946812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 9956812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9966812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9976812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9986812dfdcSPeter Maydell { 0 }, \ 9996812dfdcSPeter Maydell }; \ 10006812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 10016812dfdcSPeter Maydell } \ 10026812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 10036812dfdcSPeter Maydell { \ 10046812dfdcSPeter Maydell if (a->size > 2) { \ 10056812dfdcSPeter Maydell return false; \ 10066812dfdcSPeter Maydell } \ 10076812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 10086812dfdcSPeter Maydell } 10096812dfdcSPeter Maydell 1010cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 1011cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 10128e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 10138e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 10148e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 10158e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 10166812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 10176812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 10186812dfdcSPeter Maydell 10196812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 10206812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 10216812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 10226812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 1023059c2398SPeter Maydell 1024059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 1025059c2398SPeter Maydell { 1026059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 1027059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1028059c2398SPeter Maydell 1029059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1030059c2398SPeter Maydell return false; 1031059c2398SPeter Maydell } 1032059c2398SPeter Maydell 1033059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1034059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1035059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1036059c2398SPeter Maydell return false; 1037059c2398SPeter Maydell } 1038059c2398SPeter Maydell 1039059c2398SPeter Maydell if (a->size == 3) { 1040059c2398SPeter Maydell return false; 1041059c2398SPeter Maydell } 1042059c2398SPeter Maydell 1043059c2398SPeter Maydell if (!vfp_access_check(s)) { 1044059c2398SPeter Maydell return true; 1045059c2398SPeter Maydell } 1046059c2398SPeter Maydell 1047059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1048059c2398SPeter Maydell 1049059c2398SPeter Maydell /* 1050059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 1051059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1052059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1053059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 1054059c2398SPeter Maydell */ 1055a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 1056a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 1057a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 1058a712266fSRichard Henderson 1059a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1060a712266fSRichard Henderson read_neon_element32(tmp2, a->vn, 1, MO_32); 1061059c2398SPeter Maydell fn(tmp, tmp, tmp2); 1062059c2398SPeter Maydell 1063a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 0, MO_32); 1064a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 1065059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 1066059c2398SPeter Maydell 1067a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 0, MO_32); 1068a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 1069a712266fSRichard Henderson 1070a712266fSRichard Henderson tcg_temp_free_i32(tmp); 1071a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 1072a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 1073059c2398SPeter Maydell return true; 1074059c2398SPeter Maydell } 1075059c2398SPeter Maydell 1076059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 1077059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 1078059c2398SPeter Maydell { \ 1079059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 1080059c2398SPeter Maydell gen_helper_neon_##func##8, \ 1081059c2398SPeter Maydell gen_helper_neon_##func##16, \ 1082059c2398SPeter Maydell gen_helper_neon_##func##32, \ 1083059c2398SPeter Maydell }; \ 1084059c2398SPeter Maydell if (a->size > 2) { \ 1085059c2398SPeter Maydell return false; \ 1086059c2398SPeter Maydell } \ 1087059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 1088059c2398SPeter Maydell } 1089059c2398SPeter Maydell 1090059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 1091059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 1092059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 1093059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 1094059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 1095fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1096059c2398SPeter Maydell 1097059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1098059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1099059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1100059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1101fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 11027ecc28bcSPeter Maydell 11037ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 11047ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 11057ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 11067ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 11077ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 11087ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 11097ecc28bcSPeter Maydell { \ 11107ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 11117ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 11127ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 11137ecc28bcSPeter Maydell }; \ 11147ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 11157ecc28bcSPeter Maydell } \ 11167ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 11177ecc28bcSPeter Maydell { \ 11187ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 11197ecc28bcSPeter Maydell return false; \ 11207ecc28bcSPeter Maydell } \ 11217ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 11227ecc28bcSPeter Maydell } 11237ecc28bcSPeter Maydell 11247ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 11257ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1126a26a352bSPeter Maydell 1127e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1128e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1129a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1130a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1131a26a352bSPeter Maydell { \ 1132e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1133a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1134a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1135a26a352bSPeter Maydell tcg_temp_free_ptr(fpst); \ 1136e4a6d4a6SPeter Maydell } 1137e4a6d4a6SPeter Maydell 1138e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1139e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1140e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1141a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1142a26a352bSPeter Maydell { \ 11436cf0f240SPeter Maydell if (a->size == MO_16) { \ 1144e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1145a26a352bSPeter Maydell return false; \ 1146a26a352bSPeter Maydell } \ 1147e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1148e4a6d4a6SPeter Maydell } \ 1149e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1150a26a352bSPeter Maydell } 1151a26a352bSPeter Maydell 1152a26a352bSPeter Maydell 1153e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1154e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1155e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1156e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 1157ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h) 1158ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h) 1159ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h) 1160bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h) 1161bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h) 1162e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h) 1163e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h) 1164e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h) 1165e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h) 1166cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h) 1167cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h) 1168ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h) 116940fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h) 1170ab978335SPeter Maydell 1171e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s) 1172e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h) 1173e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s) 1174e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h) 1175e22705bbSPeter Maydell 1176d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1177d5fdf9e9SPeter Maydell { 1178d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1179d5fdf9e9SPeter Maydell return false; 1180d5fdf9e9SPeter Maydell } 1181d5fdf9e9SPeter Maydell 11826cf0f240SPeter Maydell if (a->size == MO_16) { 1183e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1184d5fdf9e9SPeter Maydell return false; 1185d5fdf9e9SPeter Maydell } 1186e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp16_3s); 1187e22705bbSPeter Maydell } 1188e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp32_3s); 1189d5fdf9e9SPeter Maydell } 1190d5fdf9e9SPeter Maydell 1191d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1192d5fdf9e9SPeter Maydell { 1193d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1194d5fdf9e9SPeter Maydell return false; 1195d5fdf9e9SPeter Maydell } 1196d5fdf9e9SPeter Maydell 11976cf0f240SPeter Maydell if (a->size == MO_16) { 1198e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1199d5fdf9e9SPeter Maydell return false; 1200d5fdf9e9SPeter Maydell } 1201e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp16_3s); 1202e22705bbSPeter Maydell } 1203e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp32_3s); 1204d5fdf9e9SPeter Maydell } 1205d5fdf9e9SPeter Maydell 12061dc587eeSPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, 12071dc587eeSPeter Maydell gen_helper_gvec_3_ptr *fn) 1208ab978335SPeter Maydell { 12091dc587eeSPeter Maydell /* FP pairwise operations */ 1210ab978335SPeter Maydell TCGv_ptr fpstatus; 1211ab978335SPeter Maydell 1212ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1213ab978335SPeter Maydell return false; 1214ab978335SPeter Maydell } 1215ab978335SPeter Maydell 1216ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1217ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1218ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1219ab978335SPeter Maydell return false; 1220ab978335SPeter Maydell } 1221ab978335SPeter Maydell 1222ab978335SPeter Maydell if (!vfp_access_check(s)) { 1223ab978335SPeter Maydell return true; 1224ab978335SPeter Maydell } 1225ab978335SPeter Maydell 1226ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1227ab978335SPeter Maydell 1228ab978335SPeter Maydell 12296cf0f240SPeter Maydell fpstatus = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 12301dc587eeSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 12311dc587eeSPeter Maydell vfp_reg_offset(1, a->vn), 12321dc587eeSPeter Maydell vfp_reg_offset(1, a->vm), 12331dc587eeSPeter Maydell fpstatus, 8, 8, 0, fn); 1234ab978335SPeter Maydell tcg_temp_free_ptr(fpstatus); 1235ab978335SPeter Maydell 1236ab978335SPeter Maydell return true; 1237ab978335SPeter Maydell } 1238ab978335SPeter Maydell 1239ab978335SPeter Maydell /* 1240ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1241ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1242ab978335SPeter Maydell */ 1243ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1244ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1245ab978335SPeter Maydell { \ 12466cf0f240SPeter Maydell if (a->size == MO_16) { \ 12471dc587eeSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1248ab978335SPeter Maydell return false; \ 1249ab978335SPeter Maydell } \ 12501dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##h); \ 12511dc587eeSPeter Maydell } \ 12521dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##s); \ 1253ab978335SPeter Maydell } 1254ab978335SPeter Maydell 12551dc587eeSPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_neon_padd) 12561dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_neon_pmax) 12571dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_neon_pmin) 1258d3c8c736SPeter Maydell 1259d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1260d3c8c736SPeter Maydell { 1261d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1262d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1263015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1264015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 1265d3c8c736SPeter Maydell 1266d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1267d3c8c736SPeter Maydell return false; 1268d3c8c736SPeter Maydell } 1269d3c8c736SPeter Maydell 1270d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1271d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1272d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1273d3c8c736SPeter Maydell return false; 1274d3c8c736SPeter Maydell } 1275d3c8c736SPeter Maydell 1276d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1277d3c8c736SPeter Maydell return false; 1278d3c8c736SPeter Maydell } 1279d3c8c736SPeter Maydell 1280d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1281d3c8c736SPeter Maydell return true; 1282d3c8c736SPeter Maydell } 1283d3c8c736SPeter Maydell 1284d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1285d3c8c736SPeter Maydell return true; 1286d3c8c736SPeter Maydell } 1287d3c8c736SPeter Maydell 1288d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1289d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1290d3c8c736SPeter Maydell { \ 1291d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1292d3c8c736SPeter Maydell } \ 1293d3c8c736SPeter Maydell 1294d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1295d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1296434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1297434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1298434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1299434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1300434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1301434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1302434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 130366432d6bSPeter Maydell 130466432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 130566432d6bSPeter Maydell { 130666432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 130766432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 130866432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 130966432d6bSPeter Maydell } 131066432d6bSPeter Maydell 131166432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 131266432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 131366432d6bSPeter Maydell { 131466432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 131566432d6bSPeter Maydell } 131666432d6bSPeter Maydell 131766432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 131866432d6bSPeter Maydell { 131966432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 132066432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 132166432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 132266432d6bSPeter Maydell } else { 132366432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 132466432d6bSPeter Maydell } 132566432d6bSPeter Maydell } 132637bfce81SPeter Maydell 132737bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 132837bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 132937bfce81SPeter Maydell { 133037bfce81SPeter Maydell /* 133137bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 133237bfce81SPeter Maydell * function needs to be passed cpu_env. 133337bfce81SPeter Maydell */ 133437bfce81SPeter Maydell TCGv_i64 constimm; 133537bfce81SPeter Maydell int pass; 133637bfce81SPeter Maydell 133737bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 133837bfce81SPeter Maydell return false; 133937bfce81SPeter Maydell } 134037bfce81SPeter Maydell 134137bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 134237bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 134337bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 134437bfce81SPeter Maydell return false; 134537bfce81SPeter Maydell } 134637bfce81SPeter Maydell 134737bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 134837bfce81SPeter Maydell return false; 134937bfce81SPeter Maydell } 135037bfce81SPeter Maydell 135137bfce81SPeter Maydell if (!vfp_access_check(s)) { 135237bfce81SPeter Maydell return true; 135337bfce81SPeter Maydell } 135437bfce81SPeter Maydell 135537bfce81SPeter Maydell /* 135637bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 135737bfce81SPeter Maydell * by immediate using the variable shift operations. 135837bfce81SPeter Maydell */ 135937bfce81SPeter Maydell constimm = tcg_const_i64(dup_const(a->size, a->shift)); 136037bfce81SPeter Maydell 136137bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 136237bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 136337bfce81SPeter Maydell 13640aa8e700SRichard Henderson read_neon_element64(tmp, a->vm, pass, MO_64); 136537bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 13660aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, pass, MO_64); 1367a4f67e18SPeter Maydell tcg_temp_free_i64(tmp); 136837bfce81SPeter Maydell } 136937bfce81SPeter Maydell tcg_temp_free_i64(constimm); 137037bfce81SPeter Maydell return true; 137137bfce81SPeter Maydell } 137237bfce81SPeter Maydell 137337bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 137437bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 137537bfce81SPeter Maydell { 137637bfce81SPeter Maydell /* 137737bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 137837bfce81SPeter Maydell * helper needs to be passed cpu_env. 137937bfce81SPeter Maydell */ 1380a712266fSRichard Henderson TCGv_i32 constimm, tmp; 138137bfce81SPeter Maydell int pass; 138237bfce81SPeter Maydell 138337bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 138437bfce81SPeter Maydell return false; 138537bfce81SPeter Maydell } 138637bfce81SPeter Maydell 138737bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 138837bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 138937bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 139037bfce81SPeter Maydell return false; 139137bfce81SPeter Maydell } 139237bfce81SPeter Maydell 139337bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 139437bfce81SPeter Maydell return false; 139537bfce81SPeter Maydell } 139637bfce81SPeter Maydell 139737bfce81SPeter Maydell if (!vfp_access_check(s)) { 139837bfce81SPeter Maydell return true; 139937bfce81SPeter Maydell } 140037bfce81SPeter Maydell 140137bfce81SPeter Maydell /* 140237bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 140337bfce81SPeter Maydell * by immediate using the variable shift operations. 140437bfce81SPeter Maydell */ 140537bfce81SPeter Maydell constimm = tcg_const_i32(dup_const(a->size, a->shift)); 1406a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 140737bfce81SPeter Maydell 140837bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 1409a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 141037bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 1411a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 141237bfce81SPeter Maydell } 1413a712266fSRichard Henderson tcg_temp_free_i32(tmp); 141437bfce81SPeter Maydell tcg_temp_free_i32(constimm); 141537bfce81SPeter Maydell return true; 141637bfce81SPeter Maydell } 141737bfce81SPeter Maydell 141837bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 141937bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 142037bfce81SPeter Maydell { \ 142137bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 142237bfce81SPeter Maydell } \ 142337bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 142437bfce81SPeter Maydell { \ 142537bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 142637bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 142737bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 142837bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 142937bfce81SPeter Maydell }; \ 143037bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 143137bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 143237bfce81SPeter Maydell } 143337bfce81SPeter Maydell 143437bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 143537bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 143637bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1437712182d3SPeter Maydell 1438712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1439712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1440712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1441712182d3SPeter Maydell { 1442712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1443712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1444712182d3SPeter Maydell TCGv_i32 rd; 1445712182d3SPeter Maydell 1446712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1447712182d3SPeter Maydell return false; 1448712182d3SPeter Maydell } 1449712182d3SPeter Maydell 1450712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1451712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1452712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1453712182d3SPeter Maydell return false; 1454712182d3SPeter Maydell } 1455712182d3SPeter Maydell 1456712182d3SPeter Maydell if (a->vm & 1) { 1457712182d3SPeter Maydell return false; 1458712182d3SPeter Maydell } 1459712182d3SPeter Maydell 1460712182d3SPeter Maydell if (!vfp_access_check(s)) { 1461712182d3SPeter Maydell return true; 1462712182d3SPeter Maydell } 1463712182d3SPeter Maydell 1464712182d3SPeter Maydell /* 1465712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1466712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1467712182d3SPeter Maydell */ 1468712182d3SPeter Maydell constimm = tcg_const_i64(-a->shift); 1469712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1470712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1471a712266fSRichard Henderson rd = tcg_temp_new_i32(); 1472712182d3SPeter Maydell 1473712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 14740aa8e700SRichard Henderson read_neon_element64(rm1, a->vm, 0, MO_64); 14750aa8e700SRichard Henderson read_neon_element64(rm2, a->vm, 1, MO_64); 1476712182d3SPeter Maydell 1477712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1478712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1479a712266fSRichard Henderson write_neon_element32(rd, a->vd, 0, MO_32); 1480712182d3SPeter Maydell 1481712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1482712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1483a712266fSRichard Henderson write_neon_element32(rd, a->vd, 1, MO_32); 1484712182d3SPeter Maydell 1485a712266fSRichard Henderson tcg_temp_free_i32(rd); 1486712182d3SPeter Maydell tcg_temp_free_i64(rm1); 1487712182d3SPeter Maydell tcg_temp_free_i64(rm2); 1488712182d3SPeter Maydell tcg_temp_free_i64(constimm); 1489712182d3SPeter Maydell 1490712182d3SPeter Maydell return true; 1491712182d3SPeter Maydell } 1492712182d3SPeter Maydell 1493712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1494712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1495712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1496712182d3SPeter Maydell { 1497712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1498712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1499712182d3SPeter Maydell TCGv_i64 rtmp; 1500712182d3SPeter Maydell uint32_t imm; 1501712182d3SPeter Maydell 1502712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1503712182d3SPeter Maydell return false; 1504712182d3SPeter Maydell } 1505712182d3SPeter Maydell 1506712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1507712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1508712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1509712182d3SPeter Maydell return false; 1510712182d3SPeter Maydell } 1511712182d3SPeter Maydell 1512712182d3SPeter Maydell if (a->vm & 1) { 1513712182d3SPeter Maydell return false; 1514712182d3SPeter Maydell } 1515712182d3SPeter Maydell 1516712182d3SPeter Maydell if (!vfp_access_check(s)) { 1517712182d3SPeter Maydell return true; 1518712182d3SPeter Maydell } 1519712182d3SPeter Maydell 1520712182d3SPeter Maydell /* 1521712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1522712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1523712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1524712182d3SPeter Maydell */ 1525712182d3SPeter Maydell if (a->size == 1) { 1526712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1527712182d3SPeter Maydell imm |= imm << 16; 1528712182d3SPeter Maydell } else { 1529712182d3SPeter Maydell /* size == 2 */ 1530712182d3SPeter Maydell imm = -a->shift; 1531712182d3SPeter Maydell } 1532712182d3SPeter Maydell constimm = tcg_const_i32(imm); 1533712182d3SPeter Maydell 1534712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1535a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1536a712266fSRichard Henderson rm2 = tcg_temp_new_i32(); 1537a712266fSRichard Henderson rm3 = tcg_temp_new_i32(); 1538a712266fSRichard Henderson rm4 = tcg_temp_new_i32(); 1539a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 0, MO_32); 1540a712266fSRichard Henderson read_neon_element32(rm2, a->vm, 1, MO_32); 1541a712266fSRichard Henderson read_neon_element32(rm3, a->vm, 2, MO_32); 1542a712266fSRichard Henderson read_neon_element32(rm4, a->vm, 3, MO_32); 1543712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1544712182d3SPeter Maydell 1545712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1546712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1547712182d3SPeter Maydell 1548712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1549712182d3SPeter Maydell tcg_temp_free_i32(rm2); 1550712182d3SPeter Maydell 1551712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1552a712266fSRichard Henderson write_neon_element32(rm1, a->vd, 0, MO_32); 1553a712266fSRichard Henderson tcg_temp_free_i32(rm1); 1554712182d3SPeter Maydell 1555712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1556712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1557712182d3SPeter Maydell tcg_temp_free_i32(constimm); 1558712182d3SPeter Maydell 1559712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1560712182d3SPeter Maydell tcg_temp_free_i32(rm4); 1561712182d3SPeter Maydell 1562712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1563712182d3SPeter Maydell tcg_temp_free_i64(rtmp); 1564a712266fSRichard Henderson write_neon_element32(rm3, a->vd, 1, MO_32); 1565a712266fSRichard Henderson tcg_temp_free_i32(rm3); 1566712182d3SPeter Maydell return true; 1567712182d3SPeter Maydell } 1568712182d3SPeter Maydell 1569712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1570712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1571712182d3SPeter Maydell { \ 1572712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1573712182d3SPeter Maydell } 1574712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1575712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1576712182d3SPeter Maydell { \ 1577712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1578712182d3SPeter Maydell } 1579712182d3SPeter Maydell 1580712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1581712182d3SPeter Maydell { 1582712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1583712182d3SPeter Maydell } 1584712182d3SPeter Maydell 1585712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1586712182d3SPeter Maydell { 1587712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1588712182d3SPeter Maydell } 1589712182d3SPeter Maydell 1590712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1591712182d3SPeter Maydell { 1592712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1593712182d3SPeter Maydell } 1594712182d3SPeter Maydell 1595712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1596712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1597712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1598712182d3SPeter Maydell 1599712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1600712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1601712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1602712182d3SPeter Maydell 1603712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1604712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1605712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1606712182d3SPeter Maydell 1607712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1608712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1609712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1610b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1611b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1612b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1613b4a3a77bSPeter Maydell 1614b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1615b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1616b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1617b4a3a77bSPeter Maydell 1618b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1619b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1620b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1621b4a3a77bSPeter Maydell 1622b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1623b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1624b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1625968bf842SPeter Maydell 1626968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1627968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1628968bf842SPeter Maydell { 1629968bf842SPeter Maydell TCGv_i64 tmp; 1630968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1631968bf842SPeter Maydell uint64_t widen_mask = 0; 1632968bf842SPeter Maydell 1633968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1634968bf842SPeter Maydell return false; 1635968bf842SPeter Maydell } 1636968bf842SPeter Maydell 1637968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1638968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1639968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1640968bf842SPeter Maydell return false; 1641968bf842SPeter Maydell } 1642968bf842SPeter Maydell 1643968bf842SPeter Maydell if (a->vd & 1) { 1644968bf842SPeter Maydell return false; 1645968bf842SPeter Maydell } 1646968bf842SPeter Maydell 1647968bf842SPeter Maydell if (!vfp_access_check(s)) { 1648968bf842SPeter Maydell return true; 1649968bf842SPeter Maydell } 1650968bf842SPeter Maydell 1651968bf842SPeter Maydell /* 1652968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1653968bf842SPeter Maydell * than the width of the source type, so after widening the input 1654968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1655968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1656968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1657968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1658968bf842SPeter Maydell */ 1659968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1660968bf842SPeter Maydell int esize = 8 << a->size; 1661968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1662968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1663968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1664968bf842SPeter Maydell } 1665968bf842SPeter Maydell 1666a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 1667a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1668a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 1669a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 1670968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1671968bf842SPeter Maydell 1672968bf842SPeter Maydell widenfn(tmp, rm0); 16739593a398SPeter Maydell tcg_temp_free_i32(rm0); 1674968bf842SPeter Maydell if (a->shift != 0) { 1675968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1676968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1677968bf842SPeter Maydell } 16780aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 0, MO_64); 1679968bf842SPeter Maydell 1680968bf842SPeter Maydell widenfn(tmp, rm1); 16819593a398SPeter Maydell tcg_temp_free_i32(rm1); 1682968bf842SPeter Maydell if (a->shift != 0) { 1683968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1684968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1685968bf842SPeter Maydell } 16860aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 1, MO_64); 1687968bf842SPeter Maydell tcg_temp_free_i64(tmp); 1688968bf842SPeter Maydell return true; 1689968bf842SPeter Maydell } 1690968bf842SPeter Maydell 1691968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1692968bf842SPeter Maydell { 1693448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1694968bf842SPeter Maydell gen_helper_neon_widen_s8, 1695968bf842SPeter Maydell gen_helper_neon_widen_s16, 1696968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1697968bf842SPeter Maydell }; 1698968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1699968bf842SPeter Maydell } 1700968bf842SPeter Maydell 1701968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1702968bf842SPeter Maydell { 1703448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1704968bf842SPeter Maydell gen_helper_neon_widen_u8, 1705968bf842SPeter Maydell gen_helper_neon_widen_u16, 1706968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1707968bf842SPeter Maydell }; 1708968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1709968bf842SPeter Maydell } 17103da26f11SPeter Maydell 17113da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 17127b959c58SPeter Maydell gen_helper_gvec_2_ptr *fn) 17133da26f11SPeter Maydell { 17143da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 17157b959c58SPeter Maydell int vec_size = a->q ? 16 : 8; 1716015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1717015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 17187b959c58SPeter Maydell TCGv_ptr fpst; 17193da26f11SPeter Maydell 17203da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17213da26f11SPeter Maydell return false; 17223da26f11SPeter Maydell } 17233da26f11SPeter Maydell 17240ae715c6SPeter Maydell if (a->size == MO_16) { 17257b959c58SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 17267b959c58SPeter Maydell return false; 17277b959c58SPeter Maydell } 17287b959c58SPeter Maydell } 17297b959c58SPeter Maydell 17303da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17313da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 17323da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 17333da26f11SPeter Maydell return false; 17343da26f11SPeter Maydell } 17353da26f11SPeter Maydell 17363da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 17373da26f11SPeter Maydell return false; 17383da26f11SPeter Maydell } 17393da26f11SPeter Maydell 17403da26f11SPeter Maydell if (!vfp_access_check(s)) { 17413da26f11SPeter Maydell return true; 17423da26f11SPeter Maydell } 17433da26f11SPeter Maydell 17440ae715c6SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 17457b959c58SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn); 17467b959c58SPeter Maydell tcg_temp_free_ptr(fpst); 17473da26f11SPeter Maydell return true; 17483da26f11SPeter Maydell } 17493da26f11SPeter Maydell 17503da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 17513da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 17523da26f11SPeter Maydell { \ 17533da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 17543da26f11SPeter Maydell } 17553da26f11SPeter Maydell 17567b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 17577b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 17587b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 17597b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) 17602c35a39eSPeter Maydell 176124018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) 176224018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) 176324018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 176424018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) 176524018cf3SPeter Maydell 17662c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) 17672c35a39eSPeter Maydell { 17682c35a39eSPeter Maydell /* 17692c35a39eSPeter Maydell * Expand the encoded constant. 17702c35a39eSPeter Maydell * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. 17712c35a39eSPeter Maydell * We choose to not special-case this and will behave as if a 17722c35a39eSPeter Maydell * valid constant encoding of 0 had been given. 17732c35a39eSPeter Maydell * cmode = 15 op = 1 must UNDEF; we assume decode has handled that. 17742c35a39eSPeter Maydell */ 17752c35a39eSPeter Maydell switch (cmode) { 17762c35a39eSPeter Maydell case 0: case 1: 17772c35a39eSPeter Maydell /* no-op */ 17782c35a39eSPeter Maydell break; 17792c35a39eSPeter Maydell case 2: case 3: 17802c35a39eSPeter Maydell imm <<= 8; 17812c35a39eSPeter Maydell break; 17822c35a39eSPeter Maydell case 4: case 5: 17832c35a39eSPeter Maydell imm <<= 16; 17842c35a39eSPeter Maydell break; 17852c35a39eSPeter Maydell case 6: case 7: 17862c35a39eSPeter Maydell imm <<= 24; 17872c35a39eSPeter Maydell break; 17882c35a39eSPeter Maydell case 8: case 9: 17892c35a39eSPeter Maydell imm |= imm << 16; 17902c35a39eSPeter Maydell break; 17912c35a39eSPeter Maydell case 10: case 11: 17922c35a39eSPeter Maydell imm = (imm << 8) | (imm << 24); 17932c35a39eSPeter Maydell break; 17942c35a39eSPeter Maydell case 12: 17952c35a39eSPeter Maydell imm = (imm << 8) | 0xff; 17962c35a39eSPeter Maydell break; 17972c35a39eSPeter Maydell case 13: 17982c35a39eSPeter Maydell imm = (imm << 16) | 0xffff; 17992c35a39eSPeter Maydell break; 18002c35a39eSPeter Maydell case 14: 18012c35a39eSPeter Maydell if (op) { 18022c35a39eSPeter Maydell /* 18032c35a39eSPeter Maydell * This is the only case where the top and bottom 32 bits 18042c35a39eSPeter Maydell * of the encoded constant differ. 18052c35a39eSPeter Maydell */ 18062c35a39eSPeter Maydell uint64_t imm64 = 0; 18072c35a39eSPeter Maydell int n; 18082c35a39eSPeter Maydell 18092c35a39eSPeter Maydell for (n = 0; n < 8; n++) { 18102c35a39eSPeter Maydell if (imm & (1 << n)) { 18112c35a39eSPeter Maydell imm64 |= (0xffULL << (n * 8)); 18122c35a39eSPeter Maydell } 18132c35a39eSPeter Maydell } 18142c35a39eSPeter Maydell return imm64; 18152c35a39eSPeter Maydell } 18162c35a39eSPeter Maydell imm |= (imm << 8) | (imm << 16) | (imm << 24); 18172c35a39eSPeter Maydell break; 18182c35a39eSPeter Maydell case 15: 18192c35a39eSPeter Maydell imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) 18202c35a39eSPeter Maydell | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); 18212c35a39eSPeter Maydell break; 18222c35a39eSPeter Maydell } 18232c35a39eSPeter Maydell if (op) { 18242c35a39eSPeter Maydell imm = ~imm; 18252c35a39eSPeter Maydell } 18262c35a39eSPeter Maydell return dup_const(MO_32, imm); 18272c35a39eSPeter Maydell } 18282c35a39eSPeter Maydell 18292c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 18302c35a39eSPeter Maydell GVecGen2iFn *fn) 18312c35a39eSPeter Maydell { 18322c35a39eSPeter Maydell uint64_t imm; 18332c35a39eSPeter Maydell int reg_ofs, vec_size; 18342c35a39eSPeter Maydell 18352c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 18362c35a39eSPeter Maydell return false; 18372c35a39eSPeter Maydell } 18382c35a39eSPeter Maydell 18392c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 18402c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 18412c35a39eSPeter Maydell return false; 18422c35a39eSPeter Maydell } 18432c35a39eSPeter Maydell 18442c35a39eSPeter Maydell if (a->vd & a->q) { 18452c35a39eSPeter Maydell return false; 18462c35a39eSPeter Maydell } 18472c35a39eSPeter Maydell 18482c35a39eSPeter Maydell if (!vfp_access_check(s)) { 18492c35a39eSPeter Maydell return true; 18502c35a39eSPeter Maydell } 18512c35a39eSPeter Maydell 1852015ee81aSRichard Henderson reg_ofs = neon_full_reg_offset(a->vd); 18532c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 18542c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 18552c35a39eSPeter Maydell 18562c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 18572c35a39eSPeter Maydell return true; 18582c35a39eSPeter Maydell } 18592c35a39eSPeter Maydell 18602c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 18612c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 18622c35a39eSPeter Maydell { 18632c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 18642c35a39eSPeter Maydell } 18652c35a39eSPeter Maydell 18662c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 18672c35a39eSPeter Maydell { 18682c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 18692c35a39eSPeter Maydell GVecGen2iFn *fn; 18702c35a39eSPeter Maydell 18712c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 18722c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 18732c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 18742c35a39eSPeter Maydell } else { 18752c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 18762c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 18772c35a39eSPeter Maydell return false; 18782c35a39eSPeter Maydell } 18792c35a39eSPeter Maydell fn = gen_VMOV_1r; 18802c35a39eSPeter Maydell } 18812c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 18822c35a39eSPeter Maydell } 1883b28be095SPeter Maydell 1884b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1885b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1886b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 18878aab18a2SRichard Henderson int src1_mop, int src2_mop) 1888b28be095SPeter Maydell { 1889b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1890b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1891b28be095SPeter Maydell 1892b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1893b28be095SPeter Maydell return false; 1894b28be095SPeter Maydell } 1895b28be095SPeter Maydell 1896b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1897b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1898b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1899b28be095SPeter Maydell return false; 1900b28be095SPeter Maydell } 1901b28be095SPeter Maydell 19028aab18a2SRichard Henderson if (!opfn) { 1903b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1904b28be095SPeter Maydell return false; 1905b28be095SPeter Maydell } 1906b28be095SPeter Maydell 19078aab18a2SRichard Henderson if ((a->vd & 1) || (src1_mop == MO_Q && (a->vn & 1))) { 1908b28be095SPeter Maydell return false; 1909b28be095SPeter Maydell } 1910b28be095SPeter Maydell 1911b28be095SPeter Maydell if (!vfp_access_check(s)) { 1912b28be095SPeter Maydell return true; 1913b28be095SPeter Maydell } 1914b28be095SPeter Maydell 1915b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1916b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1917b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1918b28be095SPeter Maydell 19198aab18a2SRichard Henderson if (src1_mop >= 0) { 19208aab18a2SRichard Henderson read_neon_element64(rn0_64, a->vn, 0, src1_mop); 1921b28be095SPeter Maydell } else { 1922a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1923a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1924b28be095SPeter Maydell widenfn(rn0_64, tmp); 1925b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1926b28be095SPeter Maydell } 19278aab18a2SRichard Henderson if (src2_mop >= 0) { 19288aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 0, src2_mop); 19298aab18a2SRichard Henderson } else { 19308aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 19318aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 19328aab18a2SRichard Henderson widenfn(rm_64, tmp); 19338aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 19348aab18a2SRichard Henderson } 1935b28be095SPeter Maydell 1936b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1937b28be095SPeter Maydell 1938b28be095SPeter Maydell /* 1939b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1940b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1941b28be095SPeter Maydell */ 19428aab18a2SRichard Henderson if (src1_mop >= 0) { 19438aab18a2SRichard Henderson read_neon_element64(rn1_64, a->vn, 1, src1_mop); 1944b28be095SPeter Maydell } else { 1945a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1946a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 1, MO_32); 1947b28be095SPeter Maydell widenfn(rn1_64, tmp); 1948b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1949b28be095SPeter Maydell } 19508aab18a2SRichard Henderson if (src2_mop >= 0) { 19518aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 1, src2_mop); 19528aab18a2SRichard Henderson } else { 19538aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 19548aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 1, MO_32); 19558aab18a2SRichard Henderson widenfn(rm_64, tmp); 19568aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 19578aab18a2SRichard Henderson } 1958b28be095SPeter Maydell 19590aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 1960b28be095SPeter Maydell 1961b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 19620aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 1963b28be095SPeter Maydell 1964b28be095SPeter Maydell tcg_temp_free_i64(rn0_64); 1965b28be095SPeter Maydell tcg_temp_free_i64(rn1_64); 1966b28be095SPeter Maydell tcg_temp_free_i64(rm_64); 1967b28be095SPeter Maydell 1968b28be095SPeter Maydell return true; 1969b28be095SPeter Maydell } 1970b28be095SPeter Maydell 19718aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN) \ 1972b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1973b28be095SPeter Maydell { \ 1974b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1975b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1976b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 19778aab18a2SRichard Henderson NULL, NULL, \ 1978b28be095SPeter Maydell }; \ 1979b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1980b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1981b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1982b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1983b28be095SPeter Maydell NULL, \ 1984b28be095SPeter Maydell }; \ 19858aab18a2SRichard Henderson int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \ 19868aab18a2SRichard Henderson return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \ 19878aab18a2SRichard Henderson SRC1WIDE ? MO_Q : narrow_mop, \ 19888aab18a2SRichard Henderson narrow_mop); \ 1989b28be095SPeter Maydell } 1990b28be095SPeter Maydell 19918aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN) 19928aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0) 19938aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN) 19948aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0) 19958aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN) 19968aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0) 19978aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN) 19988aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0) 19990fa1ab03SPeter Maydell 20000fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 20010fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 20020fa1ab03SPeter Maydell { 20030fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 20040fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 20050fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 20060fa1ab03SPeter Maydell 20070fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 20080fa1ab03SPeter Maydell return false; 20090fa1ab03SPeter Maydell } 20100fa1ab03SPeter Maydell 20110fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 20120fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 20130fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 20140fa1ab03SPeter Maydell return false; 20150fa1ab03SPeter Maydell } 20160fa1ab03SPeter Maydell 20170fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 20180fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 20190fa1ab03SPeter Maydell return false; 20200fa1ab03SPeter Maydell } 20210fa1ab03SPeter Maydell 20220fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 20230fa1ab03SPeter Maydell return false; 20240fa1ab03SPeter Maydell } 20250fa1ab03SPeter Maydell 20260fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 20270fa1ab03SPeter Maydell return true; 20280fa1ab03SPeter Maydell } 20290fa1ab03SPeter Maydell 20300fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 20310fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 20320fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 20330fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 20340fa1ab03SPeter Maydell 20350aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 0, MO_64); 20360aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 0, MO_64); 20370fa1ab03SPeter Maydell 20380fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 20390fa1ab03SPeter Maydell 20400fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 20410fa1ab03SPeter Maydell 20420aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 1, MO_64); 20430aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 1, MO_64); 20440fa1ab03SPeter Maydell 20450fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 20460fa1ab03SPeter Maydell 20470fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 20480fa1ab03SPeter Maydell 2049a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 2050a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 20510fa1ab03SPeter Maydell 2052a712266fSRichard Henderson tcg_temp_free_i32(rd0); 2053a712266fSRichard Henderson tcg_temp_free_i32(rd1); 20540fa1ab03SPeter Maydell tcg_temp_free_i64(rn_64); 20550fa1ab03SPeter Maydell tcg_temp_free_i64(rm_64); 20560fa1ab03SPeter Maydell 20570fa1ab03SPeter Maydell return true; 20580fa1ab03SPeter Maydell } 20590fa1ab03SPeter Maydell 20600fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 20610fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 20620fa1ab03SPeter Maydell { \ 20630fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 20640fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 20650fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 20660fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 20670fa1ab03SPeter Maydell NULL, \ 20680fa1ab03SPeter Maydell }; \ 20690fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 20700fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 20710fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 20720fa1ab03SPeter Maydell EXTOP, \ 20730fa1ab03SPeter Maydell NULL, \ 20740fa1ab03SPeter Maydell }; \ 20750fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 20760fa1ab03SPeter Maydell } 20770fa1ab03SPeter Maydell 20780fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 20790fa1ab03SPeter Maydell { 20800fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 20810fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 20820fa1ab03SPeter Maydell } 20830fa1ab03SPeter Maydell 20840fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 20850fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 20860fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 20870fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 2088f5b28401SPeter Maydell 2089f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 2090f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 2091f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 2092f5b28401SPeter Maydell { 2093f5b28401SPeter Maydell /* 2094f5b28401SPeter Maydell * 3-regs different lengths, long operations. 2095f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 2096f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 2097f5b28401SPeter Maydell * that result into the double-width destination. 2098f5b28401SPeter Maydell */ 2099f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 2100f5b28401SPeter Maydell TCGv_i32 rn, rm; 2101f5b28401SPeter Maydell 2102f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2103f5b28401SPeter Maydell return false; 2104f5b28401SPeter Maydell } 2105f5b28401SPeter Maydell 2106f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2107f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2108f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2109f5b28401SPeter Maydell return false; 2110f5b28401SPeter Maydell } 2111f5b28401SPeter Maydell 2112f5b28401SPeter Maydell if (!opfn) { 2113f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 2114f5b28401SPeter Maydell return false; 2115f5b28401SPeter Maydell } 2116f5b28401SPeter Maydell 2117f5b28401SPeter Maydell if (a->vd & 1) { 2118f5b28401SPeter Maydell return false; 2119f5b28401SPeter Maydell } 2120f5b28401SPeter Maydell 2121f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2122f5b28401SPeter Maydell return true; 2123f5b28401SPeter Maydell } 2124f5b28401SPeter Maydell 2125f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2126f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2127f5b28401SPeter Maydell 2128a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2129a712266fSRichard Henderson rm = tcg_temp_new_i32(); 2130a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 2131a712266fSRichard Henderson read_neon_element32(rm, a->vm, 0, MO_32); 2132f5b28401SPeter Maydell opfn(rd0, rn, rm); 2133f5b28401SPeter Maydell 2134a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 2135a712266fSRichard Henderson read_neon_element32(rm, a->vm, 1, MO_32); 2136f5b28401SPeter Maydell opfn(rd1, rn, rm); 2137f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2138f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2139f5b28401SPeter Maydell 2140f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2141f5b28401SPeter Maydell if (accfn) { 2142f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 21430aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 0, MO_64); 21449f1a5f93SRichard Henderson accfn(rd0, tmp, rd0); 21450aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 1, MO_64); 21469f1a5f93SRichard Henderson accfn(rd1, tmp, rd1); 2147f5b28401SPeter Maydell tcg_temp_free_i64(tmp); 2148f5b28401SPeter Maydell } 2149f5b28401SPeter Maydell 21509f1a5f93SRichard Henderson write_neon_element64(rd0, a->vd, 0, MO_64); 21519f1a5f93SRichard Henderson write_neon_element64(rd1, a->vd, 1, MO_64); 2152f5b28401SPeter Maydell tcg_temp_free_i64(rd0); 2153f5b28401SPeter Maydell tcg_temp_free_i64(rd1); 2154f5b28401SPeter Maydell 2155f5b28401SPeter Maydell return true; 2156f5b28401SPeter Maydell } 2157f5b28401SPeter Maydell 2158f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2159f5b28401SPeter Maydell { 2160f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2161f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2162f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2163f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2164f5b28401SPeter Maydell NULL, 2165f5b28401SPeter Maydell }; 2166f5b28401SPeter Maydell 2167f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2168f5b28401SPeter Maydell } 2169f5b28401SPeter Maydell 2170f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2171f5b28401SPeter Maydell { 2172f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2173f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2174f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2175f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2176f5b28401SPeter Maydell NULL, 2177f5b28401SPeter Maydell }; 2178f5b28401SPeter Maydell 2179f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2180f5b28401SPeter Maydell } 2181f5b28401SPeter Maydell 2182f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2183f5b28401SPeter Maydell { 2184f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2185f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2186f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2187f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2188f5b28401SPeter Maydell NULL, 2189f5b28401SPeter Maydell }; 2190f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2191f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2192f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2193f5b28401SPeter Maydell tcg_gen_add_i64, 2194f5b28401SPeter Maydell NULL, 2195f5b28401SPeter Maydell }; 2196f5b28401SPeter Maydell 2197f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2198f5b28401SPeter Maydell } 2199f5b28401SPeter Maydell 2200f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2201f5b28401SPeter Maydell { 2202f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2203f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2204f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2205f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2206f5b28401SPeter Maydell NULL, 2207f5b28401SPeter Maydell }; 2208f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2209f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2210f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2211f5b28401SPeter Maydell tcg_gen_add_i64, 2212f5b28401SPeter Maydell NULL, 2213f5b28401SPeter Maydell }; 2214f5b28401SPeter Maydell 2215f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2216f5b28401SPeter Maydell } 22173a1d9eb0SPeter Maydell 22183a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22193a1d9eb0SPeter Maydell { 22203a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 22213a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 22223a1d9eb0SPeter Maydell 22233a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 22243a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 22253a1d9eb0SPeter Maydell 22263a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 22273a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 22283a1d9eb0SPeter Maydell } 22293a1d9eb0SPeter Maydell 22303a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22313a1d9eb0SPeter Maydell { 22323a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 22333a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 22343a1d9eb0SPeter Maydell 22353a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 22363a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 22373a1d9eb0SPeter Maydell 22383a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 22393a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 22403a1d9eb0SPeter Maydell } 22413a1d9eb0SPeter Maydell 22423a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 22433a1d9eb0SPeter Maydell { 22443a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22453a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 22463a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 22473a1d9eb0SPeter Maydell gen_mull_s32, 22483a1d9eb0SPeter Maydell NULL, 22493a1d9eb0SPeter Maydell }; 22503a1d9eb0SPeter Maydell 22513a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22523a1d9eb0SPeter Maydell } 22533a1d9eb0SPeter Maydell 22543a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 22553a1d9eb0SPeter Maydell { 22563a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22573a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 22583a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 22593a1d9eb0SPeter Maydell gen_mull_u32, 22603a1d9eb0SPeter Maydell NULL, 22613a1d9eb0SPeter Maydell }; 22623a1d9eb0SPeter Maydell 22633a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22643a1d9eb0SPeter Maydell } 22653a1d9eb0SPeter Maydell 22663a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 22673a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 22683a1d9eb0SPeter Maydell { \ 22693a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 22703a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 22713a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 22723a1d9eb0SPeter Maydell gen_##MULL##32, \ 22733a1d9eb0SPeter Maydell NULL, \ 22743a1d9eb0SPeter Maydell }; \ 22753a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 22763a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 22773a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 22783a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 22793a1d9eb0SPeter Maydell NULL, \ 22803a1d9eb0SPeter Maydell }; \ 22813a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 22823a1d9eb0SPeter Maydell } 22833a1d9eb0SPeter Maydell 22843a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 22853a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 22863a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 22873a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 22889546ca59SPeter Maydell 22899546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22909546ca59SPeter Maydell { 22919546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 22929546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 22939546ca59SPeter Maydell } 22949546ca59SPeter Maydell 22959546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22969546ca59SPeter Maydell { 22979546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 22989546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 22999546ca59SPeter Maydell } 23009546ca59SPeter Maydell 23019546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 23029546ca59SPeter Maydell { 23039546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23049546ca59SPeter Maydell NULL, 23059546ca59SPeter Maydell gen_VQDMULL_16, 23069546ca59SPeter Maydell gen_VQDMULL_32, 23079546ca59SPeter Maydell NULL, 23089546ca59SPeter Maydell }; 23099546ca59SPeter Maydell 23109546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 23119546ca59SPeter Maydell } 23129546ca59SPeter Maydell 23139546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23149546ca59SPeter Maydell { 23159546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 23169546ca59SPeter Maydell } 23179546ca59SPeter Maydell 23189546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23199546ca59SPeter Maydell { 23209546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 23219546ca59SPeter Maydell } 23229546ca59SPeter Maydell 23239546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 23249546ca59SPeter Maydell { 23259546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23269546ca59SPeter Maydell NULL, 23279546ca59SPeter Maydell gen_VQDMULL_16, 23289546ca59SPeter Maydell gen_VQDMULL_32, 23299546ca59SPeter Maydell NULL, 23309546ca59SPeter Maydell }; 23319546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 23329546ca59SPeter Maydell NULL, 23339546ca59SPeter Maydell gen_VQDMLAL_acc_16, 23349546ca59SPeter Maydell gen_VQDMLAL_acc_32, 23359546ca59SPeter Maydell NULL, 23369546ca59SPeter Maydell }; 23379546ca59SPeter Maydell 23389546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 23399546ca59SPeter Maydell } 23409546ca59SPeter Maydell 23419546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23429546ca59SPeter Maydell { 23439546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 23449546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 23459546ca59SPeter Maydell } 23469546ca59SPeter Maydell 23479546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23489546ca59SPeter Maydell { 23499546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 23509546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 23519546ca59SPeter Maydell } 23529546ca59SPeter Maydell 23539546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 23549546ca59SPeter Maydell { 23559546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23569546ca59SPeter Maydell NULL, 23579546ca59SPeter Maydell gen_VQDMULL_16, 23589546ca59SPeter Maydell gen_VQDMULL_32, 23599546ca59SPeter Maydell NULL, 23609546ca59SPeter Maydell }; 23619546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 23629546ca59SPeter Maydell NULL, 23639546ca59SPeter Maydell gen_VQDMLSL_acc_16, 23649546ca59SPeter Maydell gen_VQDMLSL_acc_32, 23659546ca59SPeter Maydell NULL, 23669546ca59SPeter Maydell }; 23679546ca59SPeter Maydell 23689546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 23699546ca59SPeter Maydell } 237018fb58d5SPeter Maydell 237118fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 237218fb58d5SPeter Maydell { 237318fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 237418fb58d5SPeter Maydell 237518fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 237618fb58d5SPeter Maydell return false; 237718fb58d5SPeter Maydell } 237818fb58d5SPeter Maydell 237918fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 238018fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 238118fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 238218fb58d5SPeter Maydell return false; 238318fb58d5SPeter Maydell } 238418fb58d5SPeter Maydell 238518fb58d5SPeter Maydell if (a->vd & 1) { 238618fb58d5SPeter Maydell return false; 238718fb58d5SPeter Maydell } 238818fb58d5SPeter Maydell 238918fb58d5SPeter Maydell switch (a->size) { 239018fb58d5SPeter Maydell case 0: 239118fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 239218fb58d5SPeter Maydell break; 239318fb58d5SPeter Maydell case 2: 239418fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 239518fb58d5SPeter Maydell return false; 239618fb58d5SPeter Maydell } 239718fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 239818fb58d5SPeter Maydell break; 239918fb58d5SPeter Maydell default: 240018fb58d5SPeter Maydell return false; 240118fb58d5SPeter Maydell } 240218fb58d5SPeter Maydell 240318fb58d5SPeter Maydell if (!vfp_access_check(s)) { 240418fb58d5SPeter Maydell return true; 240518fb58d5SPeter Maydell } 240618fb58d5SPeter Maydell 2407015ee81aSRichard Henderson tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd), 2408015ee81aSRichard Henderson neon_full_reg_offset(a->vn), 2409015ee81aSRichard Henderson neon_full_reg_offset(a->vm), 241018fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 241118fb58d5SPeter Maydell return true; 241218fb58d5SPeter Maydell } 241396fc80f5SPeter Maydell 241496fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 241596fc80f5SPeter Maydell { 241696fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 241796fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 241896fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 241996fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 242096fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 242196fc80f5SPeter Maydell } 242296fc80f5SPeter Maydell 242396fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 242496fc80f5SPeter Maydell { 242596fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 242696fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 242796fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 242896fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 242996fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 243096fc80f5SPeter Maydell } 243196fc80f5SPeter Maydell 243296fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 243396fc80f5SPeter Maydell { 2434a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 2435a712266fSRichard Henderson if (size == MO_16) { 2436a712266fSRichard Henderson read_neon_element32(tmp, reg & 7, reg >> 4, MO_32); 243796fc80f5SPeter Maydell if (reg & 8) { 243896fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 243996fc80f5SPeter Maydell } else { 244096fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 244196fc80f5SPeter Maydell } 244296fc80f5SPeter Maydell } else { 2443a712266fSRichard Henderson read_neon_element32(tmp, reg & 15, reg >> 4, MO_32); 244496fc80f5SPeter Maydell } 244596fc80f5SPeter Maydell return tmp; 244696fc80f5SPeter Maydell } 244796fc80f5SPeter Maydell 244896fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 244996fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 245096fc80f5SPeter Maydell { 245196fc80f5SPeter Maydell /* 245296fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 245396fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 245496fc80f5SPeter Maydell * perform an accumulation operation of that result into the 245596fc80f5SPeter Maydell * destination. 245696fc80f5SPeter Maydell */ 2457a712266fSRichard Henderson TCGv_i32 scalar, tmp; 245896fc80f5SPeter Maydell int pass; 245996fc80f5SPeter Maydell 246096fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 246196fc80f5SPeter Maydell return false; 246296fc80f5SPeter Maydell } 246396fc80f5SPeter Maydell 246496fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 246596fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 246696fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 246796fc80f5SPeter Maydell return false; 246896fc80f5SPeter Maydell } 246996fc80f5SPeter Maydell 247096fc80f5SPeter Maydell if (!opfn) { 247196fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 247296fc80f5SPeter Maydell return false; 247396fc80f5SPeter Maydell } 247496fc80f5SPeter Maydell 247596fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 247696fc80f5SPeter Maydell return false; 247796fc80f5SPeter Maydell } 247896fc80f5SPeter Maydell 247996fc80f5SPeter Maydell if (!vfp_access_check(s)) { 248096fc80f5SPeter Maydell return true; 248196fc80f5SPeter Maydell } 248296fc80f5SPeter Maydell 248396fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2484a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 248596fc80f5SPeter Maydell 248696fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2487a712266fSRichard Henderson read_neon_element32(tmp, a->vn, pass, MO_32); 248896fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 248996fc80f5SPeter Maydell if (accfn) { 2490a712266fSRichard Henderson TCGv_i32 rd = tcg_temp_new_i32(); 2491a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 249296fc80f5SPeter Maydell accfn(tmp, rd, tmp); 249396fc80f5SPeter Maydell tcg_temp_free_i32(rd); 249496fc80f5SPeter Maydell } 2495a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 249696fc80f5SPeter Maydell } 2497a712266fSRichard Henderson tcg_temp_free_i32(tmp); 249896fc80f5SPeter Maydell tcg_temp_free_i32(scalar); 249996fc80f5SPeter Maydell return true; 250096fc80f5SPeter Maydell } 250196fc80f5SPeter Maydell 250296fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 250396fc80f5SPeter Maydell { 250496fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 250596fc80f5SPeter Maydell NULL, 250696fc80f5SPeter Maydell gen_helper_neon_mul_u16, 250796fc80f5SPeter Maydell tcg_gen_mul_i32, 250896fc80f5SPeter Maydell NULL, 250996fc80f5SPeter Maydell }; 251096fc80f5SPeter Maydell 251196fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 251296fc80f5SPeter Maydell } 251396fc80f5SPeter Maydell 251496fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 251596fc80f5SPeter Maydell { 251696fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 251796fc80f5SPeter Maydell NULL, 251896fc80f5SPeter Maydell gen_helper_neon_mul_u16, 251996fc80f5SPeter Maydell tcg_gen_mul_i32, 252096fc80f5SPeter Maydell NULL, 252196fc80f5SPeter Maydell }; 252296fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 252396fc80f5SPeter Maydell NULL, 252496fc80f5SPeter Maydell gen_helper_neon_add_u16, 252596fc80f5SPeter Maydell tcg_gen_add_i32, 252696fc80f5SPeter Maydell NULL, 252796fc80f5SPeter Maydell }; 252896fc80f5SPeter Maydell 252996fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 253096fc80f5SPeter Maydell } 253196fc80f5SPeter Maydell 253296fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 253396fc80f5SPeter Maydell { 253496fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 253596fc80f5SPeter Maydell NULL, 253696fc80f5SPeter Maydell gen_helper_neon_mul_u16, 253796fc80f5SPeter Maydell tcg_gen_mul_i32, 253896fc80f5SPeter Maydell NULL, 253996fc80f5SPeter Maydell }; 254096fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 254196fc80f5SPeter Maydell NULL, 254296fc80f5SPeter Maydell gen_helper_neon_sub_u16, 254396fc80f5SPeter Maydell tcg_gen_sub_i32, 254496fc80f5SPeter Maydell NULL, 254596fc80f5SPeter Maydell }; 254696fc80f5SPeter Maydell 254796fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 254896fc80f5SPeter Maydell } 254985ac9aefSPeter Maydell 2550fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, 2551fc8ae790SPeter Maydell gen_helper_gvec_3_ptr *fn) 2552fc8ae790SPeter Maydell { 2553fc8ae790SPeter Maydell /* Two registers and a scalar, using gvec */ 2554fc8ae790SPeter Maydell int vec_size = a->q ? 16 : 8; 2555015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 2556015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 2557fc8ae790SPeter Maydell int rm_ofs; 2558fc8ae790SPeter Maydell int idx; 2559fc8ae790SPeter Maydell TCGv_ptr fpstatus; 2560fc8ae790SPeter Maydell 2561fc8ae790SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2562fc8ae790SPeter Maydell return false; 2563fc8ae790SPeter Maydell } 2564fc8ae790SPeter Maydell 2565fc8ae790SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2566fc8ae790SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2567fc8ae790SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2568fc8ae790SPeter Maydell return false; 2569fc8ae790SPeter Maydell } 2570fc8ae790SPeter Maydell 2571fc8ae790SPeter Maydell if (!fn) { 2572fc8ae790SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2573fc8ae790SPeter Maydell return false; 2574fc8ae790SPeter Maydell } 2575fc8ae790SPeter Maydell 2576fc8ae790SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2577fc8ae790SPeter Maydell return false; 2578fc8ae790SPeter Maydell } 2579fc8ae790SPeter Maydell 2580fc8ae790SPeter Maydell if (!vfp_access_check(s)) { 2581fc8ae790SPeter Maydell return true; 2582fc8ae790SPeter Maydell } 2583fc8ae790SPeter Maydell 2584fc8ae790SPeter Maydell /* a->vm is M:Vm, which encodes both register and index */ 2585fc8ae790SPeter Maydell idx = extract32(a->vm, a->size + 2, 2); 2586fc8ae790SPeter Maydell a->vm = extract32(a->vm, 0, a->size + 2); 2587015ee81aSRichard Henderson rm_ofs = neon_full_reg_offset(a->vm); 2588fc8ae790SPeter Maydell 2589fc8ae790SPeter Maydell fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD); 2590fc8ae790SPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus, 2591fc8ae790SPeter Maydell vec_size, vec_size, idx, fn); 2592fc8ae790SPeter Maydell tcg_temp_free_ptr(fpstatus); 2593fc8ae790SPeter Maydell return true; 2594fc8ae790SPeter Maydell } 2595fc8ae790SPeter Maydell 2596fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC) \ 2597fc8ae790SPeter Maydell static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \ 259885ac9aefSPeter Maydell { \ 2599fc8ae790SPeter Maydell static gen_helper_gvec_3_ptr * const opfn[] = { \ 2600fc8ae790SPeter Maydell NULL, \ 2601fc8ae790SPeter Maydell gen_helper_##FUNC##_h, \ 2602fc8ae790SPeter Maydell gen_helper_##FUNC##_s, \ 2603fc8ae790SPeter Maydell NULL, \ 2604fc8ae790SPeter Maydell }; \ 2605fc8ae790SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \ 2606fc8ae790SPeter Maydell return false; \ 2607fc8ae790SPeter Maydell } \ 2608fc8ae790SPeter Maydell return do_2scalar_fp_vec(s, a, opfn[a->size]); \ 260985ac9aefSPeter Maydell } 261085ac9aefSPeter Maydell 2611fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx) 2612fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx) 2613fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx) 2614b2fc7be9SPeter Maydell 2615b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2616b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2617b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2618b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2619b2fc7be9SPeter Maydell 2620b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2621b2fc7be9SPeter Maydell { 2622b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2623b2fc7be9SPeter Maydell NULL, 2624b2fc7be9SPeter Maydell gen_VQDMULH_16, 2625b2fc7be9SPeter Maydell gen_VQDMULH_32, 2626b2fc7be9SPeter Maydell NULL, 2627b2fc7be9SPeter Maydell }; 2628b2fc7be9SPeter Maydell 2629b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2630b2fc7be9SPeter Maydell } 2631b2fc7be9SPeter Maydell 2632b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2633b2fc7be9SPeter Maydell { 2634b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2635b2fc7be9SPeter Maydell NULL, 2636b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2637b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2638b2fc7be9SPeter Maydell NULL, 2639b2fc7be9SPeter Maydell }; 2640b2fc7be9SPeter Maydell 2641b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2642b2fc7be9SPeter Maydell } 2643aa318f5bSPeter Maydell 2644aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2645aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2646aa318f5bSPeter Maydell { 2647aa318f5bSPeter Maydell /* 2648aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2649aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2650aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2651aa318f5bSPeter Maydell */ 2652a712266fSRichard Henderson TCGv_i32 scalar, rn, rd; 2653aa318f5bSPeter Maydell int pass; 2654aa318f5bSPeter Maydell 2655aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2656aa318f5bSPeter Maydell return false; 2657aa318f5bSPeter Maydell } 2658aa318f5bSPeter Maydell 2659aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2660aa318f5bSPeter Maydell return false; 2661aa318f5bSPeter Maydell } 2662aa318f5bSPeter Maydell 2663aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2664aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2665aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2666aa318f5bSPeter Maydell return false; 2667aa318f5bSPeter Maydell } 2668aa318f5bSPeter Maydell 2669aa318f5bSPeter Maydell if (!opfn) { 2670aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2671aa318f5bSPeter Maydell return false; 2672aa318f5bSPeter Maydell } 2673aa318f5bSPeter Maydell 2674aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2675aa318f5bSPeter Maydell return false; 2676aa318f5bSPeter Maydell } 2677aa318f5bSPeter Maydell 2678aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2679aa318f5bSPeter Maydell return true; 2680aa318f5bSPeter Maydell } 2681aa318f5bSPeter Maydell 2682aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2683a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2684a712266fSRichard Henderson rd = tcg_temp_new_i32(); 2685aa318f5bSPeter Maydell 2686aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2687a712266fSRichard Henderson read_neon_element32(rn, a->vn, pass, MO_32); 2688a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 2689aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2690a712266fSRichard Henderson write_neon_element32(rd, a->vd, pass, MO_32); 2691aa318f5bSPeter Maydell } 2692a712266fSRichard Henderson tcg_temp_free_i32(rn); 2693a712266fSRichard Henderson tcg_temp_free_i32(rd); 2694aa318f5bSPeter Maydell tcg_temp_free_i32(scalar); 2695aa318f5bSPeter Maydell 2696aa318f5bSPeter Maydell return true; 2697aa318f5bSPeter Maydell } 2698aa318f5bSPeter Maydell 2699aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2700aa318f5bSPeter Maydell { 2701aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2702aa318f5bSPeter Maydell NULL, 2703aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2704aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2705aa318f5bSPeter Maydell NULL, 2706aa318f5bSPeter Maydell }; 2707aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2708aa318f5bSPeter Maydell } 2709aa318f5bSPeter Maydell 2710aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2711aa318f5bSPeter Maydell { 2712aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2713aa318f5bSPeter Maydell NULL, 2714aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2715aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2716aa318f5bSPeter Maydell NULL, 2717aa318f5bSPeter Maydell }; 2718aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2719aa318f5bSPeter Maydell } 272077e576a9SPeter Maydell 272177e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 272277e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 272377e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 272477e576a9SPeter Maydell { 272577e576a9SPeter Maydell /* 272677e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 272777e576a9SPeter Maydell * operation on the input elements and the scalar which produces 272877e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 272977e576a9SPeter Maydell * operation of that result into the destination. 273077e576a9SPeter Maydell */ 273177e576a9SPeter Maydell TCGv_i32 scalar, rn; 273277e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 273377e576a9SPeter Maydell 273477e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 273577e576a9SPeter Maydell return false; 273677e576a9SPeter Maydell } 273777e576a9SPeter Maydell 273877e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 273977e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 274077e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 274177e576a9SPeter Maydell return false; 274277e576a9SPeter Maydell } 274377e576a9SPeter Maydell 274477e576a9SPeter Maydell if (!opfn) { 274577e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 274677e576a9SPeter Maydell return false; 274777e576a9SPeter Maydell } 274877e576a9SPeter Maydell 274977e576a9SPeter Maydell if (a->vd & 1) { 275077e576a9SPeter Maydell return false; 275177e576a9SPeter Maydell } 275277e576a9SPeter Maydell 275377e576a9SPeter Maydell if (!vfp_access_check(s)) { 275477e576a9SPeter Maydell return true; 275577e576a9SPeter Maydell } 275677e576a9SPeter Maydell 275777e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 275877e576a9SPeter Maydell 275977e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 2760a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2761a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 276277e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 276377e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 276477e576a9SPeter Maydell 2765a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 276677e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 276777e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 276877e576a9SPeter Maydell tcg_temp_free_i32(rn); 276977e576a9SPeter Maydell tcg_temp_free_i32(scalar); 277077e576a9SPeter Maydell 277177e576a9SPeter Maydell if (accfn) { 277277e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 27730aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 0, MO_64); 27749f1a5f93SRichard Henderson accfn(rn0_64, t64, rn0_64); 27750aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 1, MO_64); 27769f1a5f93SRichard Henderson accfn(rn1_64, t64, rn1_64); 277777e576a9SPeter Maydell tcg_temp_free_i64(t64); 27789f1a5f93SRichard Henderson } 27799f1a5f93SRichard Henderson 27800aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 27810aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 278277e576a9SPeter Maydell tcg_temp_free_i64(rn0_64); 278377e576a9SPeter Maydell tcg_temp_free_i64(rn1_64); 278477e576a9SPeter Maydell return true; 278577e576a9SPeter Maydell } 278677e576a9SPeter Maydell 278777e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 278877e576a9SPeter Maydell { 278977e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 279077e576a9SPeter Maydell NULL, 279177e576a9SPeter Maydell gen_helper_neon_mull_s16, 279277e576a9SPeter Maydell gen_mull_s32, 279377e576a9SPeter Maydell NULL, 279477e576a9SPeter Maydell }; 279577e576a9SPeter Maydell 279677e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 279777e576a9SPeter Maydell } 279877e576a9SPeter Maydell 279977e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 280077e576a9SPeter Maydell { 280177e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 280277e576a9SPeter Maydell NULL, 280377e576a9SPeter Maydell gen_helper_neon_mull_u16, 280477e576a9SPeter Maydell gen_mull_u32, 280577e576a9SPeter Maydell NULL, 280677e576a9SPeter Maydell }; 280777e576a9SPeter Maydell 280877e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 280977e576a9SPeter Maydell } 281077e576a9SPeter Maydell 281177e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 281277e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 281377e576a9SPeter Maydell { \ 281477e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 281577e576a9SPeter Maydell NULL, \ 281677e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 281777e576a9SPeter Maydell gen_##MULL##32, \ 281877e576a9SPeter Maydell NULL, \ 281977e576a9SPeter Maydell }; \ 282077e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 282177e576a9SPeter Maydell NULL, \ 282277e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 282377e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 282477e576a9SPeter Maydell NULL, \ 282577e576a9SPeter Maydell }; \ 282677e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 282777e576a9SPeter Maydell } 282877e576a9SPeter Maydell 282977e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 283077e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 283177e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 283277e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 283377e576a9SPeter Maydell 283477e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 283577e576a9SPeter Maydell { 283677e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 283777e576a9SPeter Maydell NULL, 283877e576a9SPeter Maydell gen_VQDMULL_16, 283977e576a9SPeter Maydell gen_VQDMULL_32, 284077e576a9SPeter Maydell NULL, 284177e576a9SPeter Maydell }; 284277e576a9SPeter Maydell 284377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 284477e576a9SPeter Maydell } 284577e576a9SPeter Maydell 284677e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 284777e576a9SPeter Maydell { 284877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 284977e576a9SPeter Maydell NULL, 285077e576a9SPeter Maydell gen_VQDMULL_16, 285177e576a9SPeter Maydell gen_VQDMULL_32, 285277e576a9SPeter Maydell NULL, 285377e576a9SPeter Maydell }; 285477e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 285577e576a9SPeter Maydell NULL, 285677e576a9SPeter Maydell gen_VQDMLAL_acc_16, 285777e576a9SPeter Maydell gen_VQDMLAL_acc_32, 285877e576a9SPeter Maydell NULL, 285977e576a9SPeter Maydell }; 286077e576a9SPeter Maydell 286177e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 286277e576a9SPeter Maydell } 286377e576a9SPeter Maydell 286477e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 286577e576a9SPeter Maydell { 286677e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 286777e576a9SPeter Maydell NULL, 286877e576a9SPeter Maydell gen_VQDMULL_16, 286977e576a9SPeter Maydell gen_VQDMULL_32, 287077e576a9SPeter Maydell NULL, 287177e576a9SPeter Maydell }; 287277e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 287377e576a9SPeter Maydell NULL, 287477e576a9SPeter Maydell gen_VQDMLSL_acc_16, 287577e576a9SPeter Maydell gen_VQDMLSL_acc_32, 287677e576a9SPeter Maydell NULL, 287777e576a9SPeter Maydell }; 287877e576a9SPeter Maydell 287977e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 288077e576a9SPeter Maydell } 28810aad761fSPeter Maydell 28820aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 28830aad761fSPeter Maydell { 28840aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 28850aad761fSPeter Maydell return false; 28860aad761fSPeter Maydell } 28870aad761fSPeter Maydell 28880aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28890aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28900aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 28910aad761fSPeter Maydell return false; 28920aad761fSPeter Maydell } 28930aad761fSPeter Maydell 28940aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 28950aad761fSPeter Maydell return false; 28960aad761fSPeter Maydell } 28970aad761fSPeter Maydell 28980aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 28990aad761fSPeter Maydell return false; 29000aad761fSPeter Maydell } 29010aad761fSPeter Maydell 29020aad761fSPeter Maydell if (!vfp_access_check(s)) { 29030aad761fSPeter Maydell return true; 29040aad761fSPeter Maydell } 29050aad761fSPeter Maydell 29060aad761fSPeter Maydell if (!a->q) { 29070aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 29080aad761fSPeter Maydell TCGv_i64 left, right, dest; 29090aad761fSPeter Maydell 29100aad761fSPeter Maydell left = tcg_temp_new_i64(); 29110aad761fSPeter Maydell right = tcg_temp_new_i64(); 29120aad761fSPeter Maydell dest = tcg_temp_new_i64(); 29130aad761fSPeter Maydell 29140aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 29150aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 29160aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 29170aa8e700SRichard Henderson write_neon_element64(dest, a->vd, 0, MO_64); 29180aad761fSPeter Maydell 29190aad761fSPeter Maydell tcg_temp_free_i64(left); 29200aad761fSPeter Maydell tcg_temp_free_i64(right); 29210aad761fSPeter Maydell tcg_temp_free_i64(dest); 29220aad761fSPeter Maydell } else { 29230aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 29240aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 29250aad761fSPeter Maydell 29260aad761fSPeter Maydell left = tcg_temp_new_i64(); 29270aad761fSPeter Maydell middle = tcg_temp_new_i64(); 29280aad761fSPeter Maydell right = tcg_temp_new_i64(); 29290aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 29300aad761fSPeter Maydell destright = tcg_temp_new_i64(); 29310aad761fSPeter Maydell 29320aad761fSPeter Maydell if (a->imm < 8) { 29330aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 29340aa8e700SRichard Henderson read_neon_element64(middle, a->vn, 1, MO_64); 29350aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 29360aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 29370aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 29380aad761fSPeter Maydell } else { 29390aa8e700SRichard Henderson read_neon_element64(right, a->vn, 1, MO_64); 29400aa8e700SRichard Henderson read_neon_element64(middle, a->vm, 0, MO_64); 29410aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 29420aa8e700SRichard Henderson read_neon_element64(left, a->vm, 1, MO_64); 29430aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 29440aad761fSPeter Maydell } 29450aad761fSPeter Maydell 29460aa8e700SRichard Henderson write_neon_element64(destright, a->vd, 0, MO_64); 29470aa8e700SRichard Henderson write_neon_element64(destleft, a->vd, 1, MO_64); 29480aad761fSPeter Maydell 29490aad761fSPeter Maydell tcg_temp_free_i64(destright); 29500aad761fSPeter Maydell tcg_temp_free_i64(destleft); 29510aad761fSPeter Maydell tcg_temp_free_i64(right); 29520aad761fSPeter Maydell tcg_temp_free_i64(middle); 29530aad761fSPeter Maydell tcg_temp_free_i64(left); 29540aad761fSPeter Maydell } 29550aad761fSPeter Maydell return true; 29560aad761fSPeter Maydell } 295754e96c74SPeter Maydell 295854e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 295954e96c74SPeter Maydell { 2960604cef3eSRichard Henderson TCGv_i64 val, def; 2961604cef3eSRichard Henderson TCGv_i32 desc; 296254e96c74SPeter Maydell 296354e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 296454e96c74SPeter Maydell return false; 296554e96c74SPeter Maydell } 296654e96c74SPeter Maydell 296754e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 296854e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 296954e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 297054e96c74SPeter Maydell return false; 297154e96c74SPeter Maydell } 297254e96c74SPeter Maydell 2973604cef3eSRichard Henderson if ((a->vn + a->len + 1) > 32) { 297454e96c74SPeter Maydell /* 297554e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 297654e96c74SPeter Maydell * helper function running off the end of the register file. 297754e96c74SPeter Maydell */ 297854e96c74SPeter Maydell return false; 297954e96c74SPeter Maydell } 2980a712266fSRichard Henderson 2981b6c56c8aSPeter Maydell if (!vfp_access_check(s)) { 2982b6c56c8aSPeter Maydell return true; 2983b6c56c8aSPeter Maydell } 2984b6c56c8aSPeter Maydell 2985604cef3eSRichard Henderson desc = tcg_const_i32((a->vn << 2) | a->len); 2986604cef3eSRichard Henderson def = tcg_temp_new_i64(); 298754e96c74SPeter Maydell if (a->op) { 2988604cef3eSRichard Henderson read_neon_element64(def, a->vd, 0, MO_64); 298954e96c74SPeter Maydell } else { 2990604cef3eSRichard Henderson tcg_gen_movi_i64(def, 0); 299154e96c74SPeter Maydell } 2992604cef3eSRichard Henderson val = tcg_temp_new_i64(); 2993604cef3eSRichard Henderson read_neon_element64(val, a->vm, 0, MO_64); 2994a712266fSRichard Henderson 2995604cef3eSRichard Henderson gen_helper_neon_tbl(val, cpu_env, desc, val, def); 2996604cef3eSRichard Henderson write_neon_element64(val, a->vd, 0, MO_64); 2997604cef3eSRichard Henderson 2998604cef3eSRichard Henderson tcg_temp_free_i64(def); 2999604cef3eSRichard Henderson tcg_temp_free_i64(val); 3000604cef3eSRichard Henderson tcg_temp_free_i32(desc); 300154e96c74SPeter Maydell return true; 300254e96c74SPeter Maydell } 30039aaa23c2SPeter Maydell 30049aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 30059aaa23c2SPeter Maydell { 30069aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30079aaa23c2SPeter Maydell return false; 30089aaa23c2SPeter Maydell } 30099aaa23c2SPeter Maydell 30109aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 30119aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 30129aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 30139aaa23c2SPeter Maydell return false; 30149aaa23c2SPeter Maydell } 30159aaa23c2SPeter Maydell 30169aaa23c2SPeter Maydell if (a->vd & a->q) { 30179aaa23c2SPeter Maydell return false; 30189aaa23c2SPeter Maydell } 30199aaa23c2SPeter Maydell 30209aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 30219aaa23c2SPeter Maydell return true; 30229aaa23c2SPeter Maydell } 30239aaa23c2SPeter Maydell 3024015ee81aSRichard Henderson tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd), 30259aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 30269aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 30279aaa23c2SPeter Maydell return true; 30289aaa23c2SPeter Maydell } 3029353d2b85SPeter Maydell 3030353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 3031353d2b85SPeter Maydell { 3032353d2b85SPeter Maydell int pass, half; 3033a712266fSRichard Henderson TCGv_i32 tmp[2]; 3034353d2b85SPeter Maydell 3035353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3036353d2b85SPeter Maydell return false; 3037353d2b85SPeter Maydell } 3038353d2b85SPeter Maydell 3039353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3040353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3041353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3042353d2b85SPeter Maydell return false; 3043353d2b85SPeter Maydell } 3044353d2b85SPeter Maydell 3045353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 3046353d2b85SPeter Maydell return false; 3047353d2b85SPeter Maydell } 3048353d2b85SPeter Maydell 3049353d2b85SPeter Maydell if (a->size == 3) { 3050353d2b85SPeter Maydell return false; 3051353d2b85SPeter Maydell } 3052353d2b85SPeter Maydell 3053353d2b85SPeter Maydell if (!vfp_access_check(s)) { 3054353d2b85SPeter Maydell return true; 3055353d2b85SPeter Maydell } 3056353d2b85SPeter Maydell 3057a712266fSRichard Henderson tmp[0] = tcg_temp_new_i32(); 3058a712266fSRichard Henderson tmp[1] = tcg_temp_new_i32(); 3059353d2b85SPeter Maydell 3060a712266fSRichard Henderson for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 3061353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 3062a712266fSRichard Henderson read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32); 3063353d2b85SPeter Maydell switch (a->size) { 3064353d2b85SPeter Maydell case 0: 3065353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 3066353d2b85SPeter Maydell break; 3067353d2b85SPeter Maydell case 1: 30688ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 3069353d2b85SPeter Maydell break; 3070353d2b85SPeter Maydell case 2: 3071353d2b85SPeter Maydell break; 3072353d2b85SPeter Maydell default: 3073353d2b85SPeter Maydell g_assert_not_reached(); 3074353d2b85SPeter Maydell } 3075353d2b85SPeter Maydell } 3076a712266fSRichard Henderson write_neon_element32(tmp[1], a->vd, pass * 2, MO_32); 3077a712266fSRichard Henderson write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32); 3078353d2b85SPeter Maydell } 3079a712266fSRichard Henderson 3080a712266fSRichard Henderson tcg_temp_free_i32(tmp[0]); 3081a712266fSRichard Henderson tcg_temp_free_i32(tmp[1]); 3082353d2b85SPeter Maydell return true; 3083353d2b85SPeter Maydell } 30846106af3aSPeter Maydell 30856106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 30866106af3aSPeter Maydell NeonGenWidenFn *widenfn, 30876106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 30886106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 30896106af3aSPeter Maydell { 30906106af3aSPeter Maydell /* 30916106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 30926106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 30936106af3aSPeter Maydell * into the destination with the accfn. 30946106af3aSPeter Maydell */ 30956106af3aSPeter Maydell int pass; 30966106af3aSPeter Maydell 30976106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30986106af3aSPeter Maydell return false; 30996106af3aSPeter Maydell } 31006106af3aSPeter Maydell 31016106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 31026106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 31036106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 31046106af3aSPeter Maydell return false; 31056106af3aSPeter Maydell } 31066106af3aSPeter Maydell 31076106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 31086106af3aSPeter Maydell return false; 31096106af3aSPeter Maydell } 31106106af3aSPeter Maydell 31116106af3aSPeter Maydell if (!widenfn) { 31126106af3aSPeter Maydell return false; 31136106af3aSPeter Maydell } 31146106af3aSPeter Maydell 31156106af3aSPeter Maydell if (!vfp_access_check(s)) { 31166106af3aSPeter Maydell return true; 31176106af3aSPeter Maydell } 31186106af3aSPeter Maydell 31196106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 31206106af3aSPeter Maydell TCGv_i32 tmp; 31216106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 31226106af3aSPeter Maydell 31236106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 31246106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 31256106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 3126a712266fSRichard Henderson 3127a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3128a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2, MO_32); 31296106af3aSPeter Maydell widenfn(rm0_64, tmp); 3130a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32); 31316106af3aSPeter Maydell widenfn(rm1_64, tmp); 31326106af3aSPeter Maydell tcg_temp_free_i32(tmp); 3133a712266fSRichard Henderson 31346106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 31356106af3aSPeter Maydell tcg_temp_free_i64(rm0_64); 31366106af3aSPeter Maydell tcg_temp_free_i64(rm1_64); 31376106af3aSPeter Maydell 31386106af3aSPeter Maydell if (accfn) { 31396106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 31400aa8e700SRichard Henderson read_neon_element64(tmp64, a->vd, pass, MO_64); 31416106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 31426106af3aSPeter Maydell tcg_temp_free_i64(tmp64); 31436106af3aSPeter Maydell } 31440aa8e700SRichard Henderson write_neon_element64(rd_64, a->vd, pass, MO_64); 31456106af3aSPeter Maydell tcg_temp_free_i64(rd_64); 31466106af3aSPeter Maydell } 31476106af3aSPeter Maydell return true; 31486106af3aSPeter Maydell } 31496106af3aSPeter Maydell 31506106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 31516106af3aSPeter Maydell { 31526106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31536106af3aSPeter Maydell gen_helper_neon_widen_s8, 31546106af3aSPeter Maydell gen_helper_neon_widen_s16, 31556106af3aSPeter Maydell tcg_gen_ext_i32_i64, 31566106af3aSPeter Maydell NULL, 31576106af3aSPeter Maydell }; 31586106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31596106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31606106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31616106af3aSPeter Maydell tcg_gen_add_i64, 31626106af3aSPeter Maydell NULL, 31636106af3aSPeter Maydell }; 31646106af3aSPeter Maydell 31656106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 31666106af3aSPeter Maydell } 31676106af3aSPeter Maydell 31686106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 31696106af3aSPeter Maydell { 31706106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31716106af3aSPeter Maydell gen_helper_neon_widen_u8, 31726106af3aSPeter Maydell gen_helper_neon_widen_u16, 31736106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31746106af3aSPeter Maydell NULL, 31756106af3aSPeter Maydell }; 31766106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31776106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31786106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31796106af3aSPeter Maydell tcg_gen_add_i64, 31806106af3aSPeter Maydell NULL, 31816106af3aSPeter Maydell }; 31826106af3aSPeter Maydell 31836106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 31846106af3aSPeter Maydell } 31856106af3aSPeter Maydell 31866106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 31876106af3aSPeter Maydell { 31886106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31896106af3aSPeter Maydell gen_helper_neon_widen_s8, 31906106af3aSPeter Maydell gen_helper_neon_widen_s16, 31916106af3aSPeter Maydell tcg_gen_ext_i32_i64, 31926106af3aSPeter Maydell NULL, 31936106af3aSPeter Maydell }; 31946106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31956106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31966106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31976106af3aSPeter Maydell tcg_gen_add_i64, 31986106af3aSPeter Maydell NULL, 31996106af3aSPeter Maydell }; 32006106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 32016106af3aSPeter Maydell gen_helper_neon_addl_u16, 32026106af3aSPeter Maydell gen_helper_neon_addl_u32, 32036106af3aSPeter Maydell tcg_gen_add_i64, 32046106af3aSPeter Maydell NULL, 32056106af3aSPeter Maydell }; 32066106af3aSPeter Maydell 32076106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 32086106af3aSPeter Maydell accfn[a->size]); 32096106af3aSPeter Maydell } 32106106af3aSPeter Maydell 32116106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 32126106af3aSPeter Maydell { 32136106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 32146106af3aSPeter Maydell gen_helper_neon_widen_u8, 32156106af3aSPeter Maydell gen_helper_neon_widen_u16, 32166106af3aSPeter Maydell tcg_gen_extu_i32_i64, 32176106af3aSPeter Maydell NULL, 32186106af3aSPeter Maydell }; 32196106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 32206106af3aSPeter Maydell gen_helper_neon_paddl_u16, 32216106af3aSPeter Maydell gen_helper_neon_paddl_u32, 32226106af3aSPeter Maydell tcg_gen_add_i64, 32236106af3aSPeter Maydell NULL, 32246106af3aSPeter Maydell }; 32256106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 32266106af3aSPeter Maydell gen_helper_neon_addl_u16, 32276106af3aSPeter Maydell gen_helper_neon_addl_u32, 32286106af3aSPeter Maydell tcg_gen_add_i64, 32296106af3aSPeter Maydell NULL, 32306106af3aSPeter Maydell }; 32316106af3aSPeter Maydell 32326106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 32336106af3aSPeter Maydell accfn[a->size]); 32346106af3aSPeter Maydell } 3235567663a2SPeter Maydell 3236567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3237567663a2SPeter Maydell 3238567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3239567663a2SPeter Maydell ZipFn *fn) 3240567663a2SPeter Maydell { 3241567663a2SPeter Maydell TCGv_ptr pd, pm; 3242567663a2SPeter Maydell 3243567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3244567663a2SPeter Maydell return false; 3245567663a2SPeter Maydell } 3246567663a2SPeter Maydell 3247567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3248567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3249567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3250567663a2SPeter Maydell return false; 3251567663a2SPeter Maydell } 3252567663a2SPeter Maydell 3253567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3254567663a2SPeter Maydell return false; 3255567663a2SPeter Maydell } 3256567663a2SPeter Maydell 3257567663a2SPeter Maydell if (!fn) { 3258567663a2SPeter Maydell /* Bad size or size/q combination */ 3259567663a2SPeter Maydell return false; 3260567663a2SPeter Maydell } 3261567663a2SPeter Maydell 3262567663a2SPeter Maydell if (!vfp_access_check(s)) { 3263567663a2SPeter Maydell return true; 3264567663a2SPeter Maydell } 3265567663a2SPeter Maydell 3266567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3267567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3268567663a2SPeter Maydell fn(pd, pm); 3269567663a2SPeter Maydell tcg_temp_free_ptr(pd); 3270567663a2SPeter Maydell tcg_temp_free_ptr(pm); 3271567663a2SPeter Maydell return true; 3272567663a2SPeter Maydell } 3273567663a2SPeter Maydell 3274567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3275567663a2SPeter Maydell { 3276567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3277567663a2SPeter Maydell { 3278567663a2SPeter Maydell gen_helper_neon_unzip8, 3279567663a2SPeter Maydell gen_helper_neon_unzip16, 3280567663a2SPeter Maydell NULL, 3281567663a2SPeter Maydell NULL, 3282567663a2SPeter Maydell }, { 3283567663a2SPeter Maydell gen_helper_neon_qunzip8, 3284567663a2SPeter Maydell gen_helper_neon_qunzip16, 3285567663a2SPeter Maydell gen_helper_neon_qunzip32, 3286567663a2SPeter Maydell NULL, 3287567663a2SPeter Maydell } 3288567663a2SPeter Maydell }; 3289567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3290567663a2SPeter Maydell } 3291567663a2SPeter Maydell 3292567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3293567663a2SPeter Maydell { 3294567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3295567663a2SPeter Maydell { 3296567663a2SPeter Maydell gen_helper_neon_zip8, 3297567663a2SPeter Maydell gen_helper_neon_zip16, 3298567663a2SPeter Maydell NULL, 3299567663a2SPeter Maydell NULL, 3300567663a2SPeter Maydell }, { 3301567663a2SPeter Maydell gen_helper_neon_qzip8, 3302567663a2SPeter Maydell gen_helper_neon_qzip16, 3303567663a2SPeter Maydell gen_helper_neon_qzip32, 3304567663a2SPeter Maydell NULL, 3305567663a2SPeter Maydell } 3306567663a2SPeter Maydell }; 3307567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3308567663a2SPeter Maydell } 33093882bdacSPeter Maydell 33103882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 33113882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 33123882bdacSPeter Maydell { 33133882bdacSPeter Maydell TCGv_i64 rm; 33143882bdacSPeter Maydell TCGv_i32 rd0, rd1; 33153882bdacSPeter Maydell 33163882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 33173882bdacSPeter Maydell return false; 33183882bdacSPeter Maydell } 33193882bdacSPeter Maydell 33203882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 33213882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 33223882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 33233882bdacSPeter Maydell return false; 33243882bdacSPeter Maydell } 33253882bdacSPeter Maydell 33263882bdacSPeter Maydell if (a->vm & 1) { 33273882bdacSPeter Maydell return false; 33283882bdacSPeter Maydell } 33293882bdacSPeter Maydell 33303882bdacSPeter Maydell if (!narrowfn) { 33313882bdacSPeter Maydell return false; 33323882bdacSPeter Maydell } 33333882bdacSPeter Maydell 33343882bdacSPeter Maydell if (!vfp_access_check(s)) { 33353882bdacSPeter Maydell return true; 33363882bdacSPeter Maydell } 33373882bdacSPeter Maydell 33383882bdacSPeter Maydell rm = tcg_temp_new_i64(); 33393882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 33403882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 33413882bdacSPeter Maydell 33420aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 0, MO_64); 33433882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 33440aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 1, MO_64); 33453882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 3346a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 3347a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 3348a712266fSRichard Henderson tcg_temp_free_i32(rd0); 3349a712266fSRichard Henderson tcg_temp_free_i32(rd1); 33503882bdacSPeter Maydell tcg_temp_free_i64(rm); 33513882bdacSPeter Maydell return true; 33523882bdacSPeter Maydell } 33533882bdacSPeter Maydell 33543882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 33553882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 33563882bdacSPeter Maydell { \ 33573882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 33583882bdacSPeter Maydell FUNC##8, \ 33593882bdacSPeter Maydell FUNC##16, \ 33603882bdacSPeter Maydell FUNC##32, \ 33613882bdacSPeter Maydell NULL, \ 33623882bdacSPeter Maydell }; \ 33633882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 33643882bdacSPeter Maydell } 33653882bdacSPeter Maydell 33663882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 33673882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 33683882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 33693882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3370749e2be3SPeter Maydell 3371749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3372749e2be3SPeter Maydell { 3373749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3374749e2be3SPeter Maydell TCGv_i64 rd; 3375749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3376749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3377749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3378749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3379749e2be3SPeter Maydell NULL, 3380749e2be3SPeter Maydell }; 3381749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3382749e2be3SPeter Maydell 3383749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3384749e2be3SPeter Maydell return false; 3385749e2be3SPeter Maydell } 3386749e2be3SPeter Maydell 3387749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3388749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3389749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3390749e2be3SPeter Maydell return false; 3391749e2be3SPeter Maydell } 3392749e2be3SPeter Maydell 3393749e2be3SPeter Maydell if (a->vd & 1) { 3394749e2be3SPeter Maydell return false; 3395749e2be3SPeter Maydell } 3396749e2be3SPeter Maydell 3397749e2be3SPeter Maydell if (!widenfn) { 3398749e2be3SPeter Maydell return false; 3399749e2be3SPeter Maydell } 3400749e2be3SPeter Maydell 3401749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3402749e2be3SPeter Maydell return true; 3403749e2be3SPeter Maydell } 3404749e2be3SPeter Maydell 3405749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3406a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 3407a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 3408749e2be3SPeter Maydell 3409a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 3410a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 3411749e2be3SPeter Maydell 3412749e2be3SPeter Maydell widenfn(rd, rm0); 3413749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 34140aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 0, MO_64); 3415749e2be3SPeter Maydell widenfn(rd, rm1); 3416749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 34170aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 1, MO_64); 3418749e2be3SPeter Maydell 3419749e2be3SPeter Maydell tcg_temp_free_i64(rd); 3420749e2be3SPeter Maydell tcg_temp_free_i32(rm0); 3421749e2be3SPeter Maydell tcg_temp_free_i32(rm1); 3422749e2be3SPeter Maydell return true; 3423749e2be3SPeter Maydell } 3424654a5173SPeter Maydell 3425654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3426654a5173SPeter Maydell { 3427654a5173SPeter Maydell TCGv_ptr fpst; 3428654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3429654a5173SPeter Maydell 3430654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3431654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3432654a5173SPeter Maydell return false; 3433654a5173SPeter Maydell } 3434654a5173SPeter Maydell 3435654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3436654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3437654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3438654a5173SPeter Maydell return false; 3439654a5173SPeter Maydell } 3440654a5173SPeter Maydell 3441654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3442654a5173SPeter Maydell return false; 3443654a5173SPeter Maydell } 3444654a5173SPeter Maydell 3445654a5173SPeter Maydell if (!vfp_access_check(s)) { 3446654a5173SPeter Maydell return true; 3447654a5173SPeter Maydell } 3448654a5173SPeter Maydell 3449a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3450654a5173SPeter Maydell ahp = get_ahp_flag(); 3451a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3452a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3453654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3454a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3455a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3456654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3457654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3458654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3459a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 2, MO_32); 3460654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3461a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 3462a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 3, MO_32); 3463a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 0, MO_32); 3464a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3465654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3466654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3467654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3468a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 3469a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3470654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3471654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3472654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3473654a5173SPeter Maydell 3474654a5173SPeter Maydell return true; 3475654a5173SPeter Maydell } 3476654a5173SPeter Maydell 3477654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3478654a5173SPeter Maydell { 3479654a5173SPeter Maydell TCGv_ptr fpst; 3480654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3481654a5173SPeter Maydell 3482654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3483654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3484654a5173SPeter Maydell return false; 3485654a5173SPeter Maydell } 3486654a5173SPeter Maydell 3487654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3488654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3489654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3490654a5173SPeter Maydell return false; 3491654a5173SPeter Maydell } 3492654a5173SPeter Maydell 3493654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3494654a5173SPeter Maydell return false; 3495654a5173SPeter Maydell } 3496654a5173SPeter Maydell 3497654a5173SPeter Maydell if (!vfp_access_check(s)) { 3498654a5173SPeter Maydell return true; 3499654a5173SPeter Maydell } 3500654a5173SPeter Maydell 3501a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3502654a5173SPeter Maydell ahp = get_ahp_flag(); 3503654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3504a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3505a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3506a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3507a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3508654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3509654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3510a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 0, MO_32); 3511654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3512654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3513a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 1, MO_32); 3514a712266fSRichard Henderson tcg_temp_free_i32(tmp); 3515654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3516654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3517a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 2, MO_32); 3518a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3519654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3520654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3521a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 3, MO_32); 3522a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3523654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3524654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3525654a5173SPeter Maydell 3526654a5173SPeter Maydell return true; 3527654a5173SPeter Maydell } 352875153179SPeter Maydell 352975153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 353075153179SPeter Maydell { 353175153179SPeter Maydell int vec_size = a->q ? 16 : 8; 3532015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 3533015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 353475153179SPeter Maydell 353575153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 353675153179SPeter Maydell return false; 353775153179SPeter Maydell } 353875153179SPeter Maydell 353975153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 354075153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 354175153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 354275153179SPeter Maydell return false; 354375153179SPeter Maydell } 354475153179SPeter Maydell 354575153179SPeter Maydell if (a->size == 3) { 354675153179SPeter Maydell return false; 354775153179SPeter Maydell } 354875153179SPeter Maydell 354975153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 355075153179SPeter Maydell return false; 355175153179SPeter Maydell } 355275153179SPeter Maydell 355375153179SPeter Maydell if (!vfp_access_check(s)) { 355475153179SPeter Maydell return true; 355575153179SPeter Maydell } 355675153179SPeter Maydell 355775153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 355875153179SPeter Maydell 355975153179SPeter Maydell return true; 356075153179SPeter Maydell } 356175153179SPeter Maydell 356275153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 356375153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 356475153179SPeter Maydell { \ 356575153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 356675153179SPeter Maydell } 356775153179SPeter Maydell 356875153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 356975153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 357075153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 357175153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 357275153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 357375153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 357475153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 357575153179SPeter Maydell 357675153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 357775153179SPeter Maydell { 357875153179SPeter Maydell if (a->size != 0) { 357975153179SPeter Maydell return false; 358075153179SPeter Maydell } 358175153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 358275153179SPeter Maydell } 35830b30dd5bSPeter Maydell 35840b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 35850b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35860b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35870b30dd5bSPeter Maydell uint32_t maxsz) \ 35880b30dd5bSPeter Maydell { \ 35890b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 35900b30dd5bSPeter Maydell DATA, FUNC); \ 35910b30dd5bSPeter Maydell } 35920b30dd5bSPeter Maydell 35930b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 35940b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35950b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35960b30dd5bSPeter Maydell uint32_t maxsz) \ 35970b30dd5bSPeter Maydell { \ 35980b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 35990b30dd5bSPeter Maydell } 36000b30dd5bSPeter Maydell 36010b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 36020b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 36030b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 36040b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 36050b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 36060b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 36070b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 36080b30dd5bSPeter Maydell 36090b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 36100b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 36110b30dd5bSPeter Maydell { \ 36120b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 36130b30dd5bSPeter Maydell return false; \ 36140b30dd5bSPeter Maydell } \ 36150b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 36160b30dd5bSPeter Maydell } 36170b30dd5bSPeter Maydell 36180b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 36190b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 36200b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 36210b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 36220b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 36230b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 36240b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 362589668082SPeter Maydell 362689668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 362789668082SPeter Maydell { 3628a712266fSRichard Henderson TCGv_i32 tmp; 362989668082SPeter Maydell int pass; 363089668082SPeter Maydell 363189668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 363289668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 363389668082SPeter Maydell return false; 363489668082SPeter Maydell } 363589668082SPeter Maydell 363689668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 363789668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 363889668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 363989668082SPeter Maydell return false; 364089668082SPeter Maydell } 364189668082SPeter Maydell 364289668082SPeter Maydell if (!fn) { 364389668082SPeter Maydell return false; 364489668082SPeter Maydell } 364589668082SPeter Maydell 364689668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 364789668082SPeter Maydell return false; 364889668082SPeter Maydell } 364989668082SPeter Maydell 365089668082SPeter Maydell if (!vfp_access_check(s)) { 365189668082SPeter Maydell return true; 365289668082SPeter Maydell } 365389668082SPeter Maydell 3654a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 365589668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3656a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 365789668082SPeter Maydell fn(tmp, tmp); 3658a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 365989668082SPeter Maydell } 3660a712266fSRichard Henderson tcg_temp_free_i32(tmp); 366189668082SPeter Maydell 366289668082SPeter Maydell return true; 366389668082SPeter Maydell } 366489668082SPeter Maydell 366589668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 366689668082SPeter Maydell { 366789668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 366889668082SPeter Maydell tcg_gen_bswap32_i32, 366989668082SPeter Maydell gen_swap_half, 367089668082SPeter Maydell NULL, 367189668082SPeter Maydell NULL, 367289668082SPeter Maydell }; 367389668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 367489668082SPeter Maydell } 367589668082SPeter Maydell 367689668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 367789668082SPeter Maydell { 367889668082SPeter Maydell if (a->size != 0) { 367989668082SPeter Maydell return false; 368089668082SPeter Maydell } 368189668082SPeter Maydell return do_2misc(s, a, gen_rev16); 368289668082SPeter Maydell } 368384eae770SPeter Maydell 368484eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 368584eae770SPeter Maydell { 368684eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 368784eae770SPeter Maydell gen_helper_neon_cls_s8, 368884eae770SPeter Maydell gen_helper_neon_cls_s16, 368984eae770SPeter Maydell gen_helper_neon_cls_s32, 369084eae770SPeter Maydell NULL, 369184eae770SPeter Maydell }; 369284eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 369384eae770SPeter Maydell } 369484eae770SPeter Maydell 369584eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 369684eae770SPeter Maydell { 369784eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 369884eae770SPeter Maydell } 369984eae770SPeter Maydell 370084eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 370184eae770SPeter Maydell { 370284eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 370384eae770SPeter Maydell gen_helper_neon_clz_u8, 370484eae770SPeter Maydell gen_helper_neon_clz_u16, 370584eae770SPeter Maydell do_VCLZ_32, 370684eae770SPeter Maydell NULL, 370784eae770SPeter Maydell }; 370884eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 370984eae770SPeter Maydell } 371084eae770SPeter Maydell 371184eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 371284eae770SPeter Maydell { 371384eae770SPeter Maydell if (a->size != 0) { 371484eae770SPeter Maydell return false; 371584eae770SPeter Maydell } 371684eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 371784eae770SPeter Maydell } 371884eae770SPeter Maydell 37192b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 37202b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 37212b70d8cdSPeter Maydell { 37222b70d8cdSPeter Maydell tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs, 37232b70d8cdSPeter Maydell vece == MO_16 ? 0x7fff : 0x7fffffff, 37242b70d8cdSPeter Maydell oprsz, maxsz); 37252b70d8cdSPeter Maydell } 37262b70d8cdSPeter Maydell 372784eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 372884eae770SPeter Maydell { 37292b70d8cdSPeter Maydell if (a->size == MO_16) { 37302b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 373184eae770SPeter Maydell return false; 373284eae770SPeter Maydell } 37332b70d8cdSPeter Maydell } else if (a->size != MO_32) { 37342b70d8cdSPeter Maydell return false; 37352b70d8cdSPeter Maydell } 37362b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VABS_F); 37372b70d8cdSPeter Maydell } 37382b70d8cdSPeter Maydell 37392b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 37402b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 37412b70d8cdSPeter Maydell { 37422b70d8cdSPeter Maydell tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs, 37432b70d8cdSPeter Maydell vece == MO_16 ? 0x8000 : 0x80000000, 37442b70d8cdSPeter Maydell oprsz, maxsz); 374584eae770SPeter Maydell } 374684eae770SPeter Maydell 374784eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 374884eae770SPeter Maydell { 37492b70d8cdSPeter Maydell if (a->size == MO_16) { 37502b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 375184eae770SPeter Maydell return false; 375284eae770SPeter Maydell } 37532b70d8cdSPeter Maydell } else if (a->size != MO_32) { 37542b70d8cdSPeter Maydell return false; 37552b70d8cdSPeter Maydell } 37562b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VNEG_F); 375784eae770SPeter Maydell } 375884eae770SPeter Maydell 375984eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 376084eae770SPeter Maydell { 376184eae770SPeter Maydell if (a->size != 2) { 376284eae770SPeter Maydell return false; 376384eae770SPeter Maydell } 376484eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 376584eae770SPeter Maydell } 376684eae770SPeter Maydell 376784eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 376884eae770SPeter Maydell { 376984eae770SPeter Maydell if (a->size != 2) { 377084eae770SPeter Maydell return false; 377184eae770SPeter Maydell } 377284eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 377384eae770SPeter Maydell } 37744936f38aSPeter Maydell 37754936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 37764936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 37774936f38aSPeter Maydell { \ 37784936f38aSPeter Maydell FUNC(d, cpu_env, m); \ 37794936f38aSPeter Maydell } 37804936f38aSPeter Maydell 37814936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 37824936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 37834936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 37844936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 37854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 37864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 37874936f38aSPeter Maydell 37884936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 37894936f38aSPeter Maydell { 37904936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 37914936f38aSPeter Maydell gen_VQABS_s8, 37924936f38aSPeter Maydell gen_VQABS_s16, 37934936f38aSPeter Maydell gen_VQABS_s32, 37944936f38aSPeter Maydell NULL, 37954936f38aSPeter Maydell }; 37964936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 37974936f38aSPeter Maydell } 37984936f38aSPeter Maydell 37994936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 38004936f38aSPeter Maydell { 38014936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 38024936f38aSPeter Maydell gen_VQNEG_s8, 38034936f38aSPeter Maydell gen_VQNEG_s16, 38044936f38aSPeter Maydell gen_VQNEG_s32, 38054936f38aSPeter Maydell NULL, 38064936f38aSPeter Maydell }; 38074936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 38084936f38aSPeter Maydell } 38093e96b205SPeter Maydell 38104a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC) \ 38114a15d9a3SPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 38124a15d9a3SPeter Maydell uint32_t rm_ofs, \ 38134a15d9a3SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 38144a15d9a3SPeter Maydell { \ 38154a15d9a3SPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 38164a15d9a3SPeter Maydell NULL, HFUNC, SFUNC, NULL, \ 38174a15d9a3SPeter Maydell }; \ 38184a15d9a3SPeter Maydell TCGv_ptr fpst; \ 38194a15d9a3SPeter Maydell fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD); \ 38204a15d9a3SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0, \ 38214a15d9a3SPeter Maydell fns[vece]); \ 38224a15d9a3SPeter Maydell tcg_temp_free_ptr(fpst); \ 38234a15d9a3SPeter Maydell } \ 38244a15d9a3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 38254a15d9a3SPeter Maydell { \ 38264a15d9a3SPeter Maydell if (a->size == MO_16) { \ 38274a15d9a3SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 38284a15d9a3SPeter Maydell return false; \ 38294a15d9a3SPeter Maydell } \ 38304a15d9a3SPeter Maydell } else if (a->size != MO_32) { \ 38314a15d9a3SPeter Maydell return false; \ 38324a15d9a3SPeter Maydell } \ 38334a15d9a3SPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 38344a15d9a3SPeter Maydell } 38354a15d9a3SPeter Maydell 38364a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s) 38374a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s) 3838635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s) 3839635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s) 3840635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s) 3841635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s) 3842635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s) 38437782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos) 38447782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos) 38457782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs) 38467782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs) 38474a15d9a3SPeter Maydell 384823afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s) 384923afcdd2SPeter Maydell 38503e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 38513e96b205SPeter Maydell { 38523e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 38533e96b205SPeter Maydell return false; 38543e96b205SPeter Maydell } 385523afcdd2SPeter Maydell return trans_VRINTX_impl(s, a); 38563e96b205SPeter Maydell } 3857baa59323SPeter Maydell 3858ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP) \ 3859ca88a6efSPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 3860ca88a6efSPeter Maydell uint32_t rm_ofs, \ 3861ca88a6efSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 3862ca88a6efSPeter Maydell { \ 3863ca88a6efSPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 3864ca88a6efSPeter Maydell NULL, \ 3865ca88a6efSPeter Maydell gen_helper_gvec_##OP##h, \ 3866ca88a6efSPeter Maydell gen_helper_gvec_##OP##s, \ 3867ca88a6efSPeter Maydell NULL, \ 3868ca88a6efSPeter Maydell }; \ 3869ca88a6efSPeter Maydell TCGv_ptr fpst; \ 3870ca88a6efSPeter Maydell fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD); \ 3871ca88a6efSPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, \ 3872ca88a6efSPeter Maydell arm_rmode_to_sf(RMODE), fns[vece]); \ 3873ca88a6efSPeter Maydell tcg_temp_free_ptr(fpst); \ 3874ca88a6efSPeter Maydell } \ 3875a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3876a183d5fbSPeter Maydell { \ 3877ca88a6efSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { \ 3878ca88a6efSPeter Maydell return false; \ 3879ca88a6efSPeter Maydell } \ 3880ca88a6efSPeter Maydell if (a->size == MO_16) { \ 3881ca88a6efSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 3882ca88a6efSPeter Maydell return false; \ 3883ca88a6efSPeter Maydell } \ 3884ca88a6efSPeter Maydell } else if (a->size != MO_32) { \ 3885ca88a6efSPeter Maydell return false; \ 3886ca88a6efSPeter Maydell } \ 3887ca88a6efSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 3888a183d5fbSPeter Maydell } 3889a183d5fbSPeter Maydell 3890ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u) 3891ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s) 3892ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u) 3893ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s) 3894ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u) 3895ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s) 3896ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u) 3897ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s) 38988ab3a227SPeter Maydell 389918725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_) 390018725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_) 390118725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_) 390218725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_) 390318725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_) 390418725916SPeter Maydell 39058ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 39068ab3a227SPeter Maydell { 39078ab3a227SPeter Maydell TCGv_i64 rm, rd; 39088ab3a227SPeter Maydell int pass; 39098ab3a227SPeter Maydell 39108ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 39118ab3a227SPeter Maydell return false; 39128ab3a227SPeter Maydell } 39138ab3a227SPeter Maydell 39148ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 39158ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 39168ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 39178ab3a227SPeter Maydell return false; 39188ab3a227SPeter Maydell } 39198ab3a227SPeter Maydell 39208ab3a227SPeter Maydell if (a->size != 0) { 39218ab3a227SPeter Maydell return false; 39228ab3a227SPeter Maydell } 39238ab3a227SPeter Maydell 39248ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 39258ab3a227SPeter Maydell return false; 39268ab3a227SPeter Maydell } 39278ab3a227SPeter Maydell 39288ab3a227SPeter Maydell if (!vfp_access_check(s)) { 39298ab3a227SPeter Maydell return true; 39308ab3a227SPeter Maydell } 39318ab3a227SPeter Maydell 39328ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 39338ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 39348ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 39350aa8e700SRichard Henderson read_neon_element64(rm, a->vm, pass, MO_64); 39360aa8e700SRichard Henderson read_neon_element64(rd, a->vd, pass, MO_64); 39370aa8e700SRichard Henderson write_neon_element64(rm, a->vd, pass, MO_64); 39380aa8e700SRichard Henderson write_neon_element64(rd, a->vm, pass, MO_64); 39398ab3a227SPeter Maydell } 39408ab3a227SPeter Maydell tcg_temp_free_i64(rm); 39418ab3a227SPeter Maydell tcg_temp_free_i64(rd); 39428ab3a227SPeter Maydell 39438ab3a227SPeter Maydell return true; 39448ab3a227SPeter Maydell } 3945d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 3946d4366190SPeter Maydell { 3947d4366190SPeter Maydell TCGv_i32 rd, tmp; 3948d4366190SPeter Maydell 3949d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3950d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3951d4366190SPeter Maydell 3952d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 3953d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 3954d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 3955d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3956d4366190SPeter Maydell 3957d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 3958d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 3959d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 3960d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3961d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3962d4366190SPeter Maydell 3963d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3964d4366190SPeter Maydell tcg_temp_free_i32(rd); 3965d4366190SPeter Maydell } 3966d4366190SPeter Maydell 3967d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 3968d4366190SPeter Maydell { 3969d4366190SPeter Maydell TCGv_i32 rd, tmp; 3970d4366190SPeter Maydell 3971d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3972d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3973d4366190SPeter Maydell 3974d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 3975d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 3976d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3977d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 3978d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 3979d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3980d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3981d4366190SPeter Maydell 3982d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3983d4366190SPeter Maydell tcg_temp_free_i32(rd); 3984d4366190SPeter Maydell } 3985d4366190SPeter Maydell 3986d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 3987d4366190SPeter Maydell { 3988d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 3989d4366190SPeter Maydell int pass; 3990d4366190SPeter Maydell 3991d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3992d4366190SPeter Maydell return false; 3993d4366190SPeter Maydell } 3994d4366190SPeter Maydell 3995d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3996d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3997d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3998d4366190SPeter Maydell return false; 3999d4366190SPeter Maydell } 4000d4366190SPeter Maydell 4001d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 4002d4366190SPeter Maydell return false; 4003d4366190SPeter Maydell } 4004d4366190SPeter Maydell 4005d4366190SPeter Maydell if (a->size == 3) { 4006d4366190SPeter Maydell return false; 4007d4366190SPeter Maydell } 4008d4366190SPeter Maydell 4009d4366190SPeter Maydell if (!vfp_access_check(s)) { 4010d4366190SPeter Maydell return true; 4011d4366190SPeter Maydell } 4012d4366190SPeter Maydell 4013a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 4014a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 4015a712266fSRichard Henderson if (a->size == MO_32) { 4016d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 4017a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 4018a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass + 1, MO_32); 4019a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 4020a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass + 1, MO_32); 4021d4366190SPeter Maydell } 4022d4366190SPeter Maydell } else { 4023d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 4024a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 4025a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass, MO_32); 4026a712266fSRichard Henderson if (a->size == MO_8) { 4027d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 4028d4366190SPeter Maydell } else { 4029d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 4030d4366190SPeter Maydell } 4031a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 4032a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 4033d4366190SPeter Maydell } 4034d4366190SPeter Maydell } 4035a712266fSRichard Henderson tcg_temp_free_i32(tmp); 4036a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 4037d4366190SPeter Maydell return true; 4038d4366190SPeter Maydell } 4039