1625e3dd4SPeter Maydell /* 2625e3dd4SPeter Maydell * ARM translation: AArch32 Neon instructions 3625e3dd4SPeter Maydell * 4625e3dd4SPeter Maydell * Copyright (c) 2003 Fabrice Bellard 5625e3dd4SPeter Maydell * Copyright (c) 2005-2007 CodeSourcery 6625e3dd4SPeter Maydell * Copyright (c) 2007 OpenedHand, Ltd. 7625e3dd4SPeter Maydell * Copyright (c) 2020 Linaro, Ltd. 8625e3dd4SPeter Maydell * 9625e3dd4SPeter Maydell * This library is free software; you can redistribute it and/or 10625e3dd4SPeter Maydell * modify it under the terms of the GNU Lesser General Public 11625e3dd4SPeter Maydell * License as published by the Free Software Foundation; either 1250f57e09SChetan Pant * version 2.1 of the License, or (at your option) any later version. 13625e3dd4SPeter Maydell * 14625e3dd4SPeter Maydell * This library is distributed in the hope that it will be useful, 15625e3dd4SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 16625e3dd4SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17625e3dd4SPeter Maydell * Lesser General Public License for more details. 18625e3dd4SPeter Maydell * 19625e3dd4SPeter Maydell * You should have received a copy of the GNU Lesser General Public 20625e3dd4SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21625e3dd4SPeter Maydell */ 22625e3dd4SPeter Maydell 234800b852SPeter Maydell #include "qemu/osdep.h" 244800b852SPeter Maydell #include "tcg/tcg-op.h" 254800b852SPeter Maydell #include "tcg/tcg-op-gvec.h" 264800b852SPeter Maydell #include "exec/exec-all.h" 274800b852SPeter Maydell #include "exec/gen-icount.h" 284800b852SPeter Maydell #include "translate.h" 294800b852SPeter Maydell #include "translate-a32.h" 30625e3dd4SPeter Maydell 31625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 32139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc" 33139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc" 34139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc" 35afff8de0SPeter Maydell 36eb554d61SPeter Maydell static TCGv_ptr vfp_reg_ptr(bool dp, int reg) 37eb554d61SPeter Maydell { 38eb554d61SPeter Maydell TCGv_ptr ret = tcg_temp_new_ptr(); 39eb554d61SPeter Maydell tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); 40eb554d61SPeter Maydell return ret; 41eb554d61SPeter Maydell } 42eb554d61SPeter Maydell 436fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) 446fb57878SPeter Maydell { 456fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 466fb57878SPeter Maydell 476fb57878SPeter Maydell switch (mop) { 486fb57878SPeter Maydell case MO_UB: 496fb57878SPeter Maydell tcg_gen_ld8u_i32(var, cpu_env, offset); 506fb57878SPeter Maydell break; 516fb57878SPeter Maydell case MO_UW: 526fb57878SPeter Maydell tcg_gen_ld16u_i32(var, cpu_env, offset); 536fb57878SPeter Maydell break; 546fb57878SPeter Maydell case MO_UL: 556fb57878SPeter Maydell tcg_gen_ld_i32(var, cpu_env, offset); 566fb57878SPeter Maydell break; 576fb57878SPeter Maydell default: 586fb57878SPeter Maydell g_assert_not_reached(); 596fb57878SPeter Maydell } 606fb57878SPeter Maydell } 616fb57878SPeter Maydell 626fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) 636fb57878SPeter Maydell { 646fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 656fb57878SPeter Maydell 666fb57878SPeter Maydell switch (mop) { 676fb57878SPeter Maydell case MO_UB: 686fb57878SPeter Maydell tcg_gen_ld8u_i64(var, cpu_env, offset); 696fb57878SPeter Maydell break; 706fb57878SPeter Maydell case MO_UW: 716fb57878SPeter Maydell tcg_gen_ld16u_i64(var, cpu_env, offset); 726fb57878SPeter Maydell break; 736fb57878SPeter Maydell case MO_UL: 746fb57878SPeter Maydell tcg_gen_ld32u_i64(var, cpu_env, offset); 756fb57878SPeter Maydell break; 76fc313c64SFrédéric Pétrot case MO_UQ: 776fb57878SPeter Maydell tcg_gen_ld_i64(var, cpu_env, offset); 786fb57878SPeter Maydell break; 796fb57878SPeter Maydell default: 806fb57878SPeter Maydell g_assert_not_reached(); 816fb57878SPeter Maydell } 826fb57878SPeter Maydell } 836fb57878SPeter Maydell 846fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) 856fb57878SPeter Maydell { 866fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 876fb57878SPeter Maydell 886fb57878SPeter Maydell switch (size) { 896fb57878SPeter Maydell case MO_8: 906fb57878SPeter Maydell tcg_gen_st8_i32(var, cpu_env, offset); 916fb57878SPeter Maydell break; 926fb57878SPeter Maydell case MO_16: 936fb57878SPeter Maydell tcg_gen_st16_i32(var, cpu_env, offset); 946fb57878SPeter Maydell break; 956fb57878SPeter Maydell case MO_32: 966fb57878SPeter Maydell tcg_gen_st_i32(var, cpu_env, offset); 976fb57878SPeter Maydell break; 986fb57878SPeter Maydell default: 996fb57878SPeter Maydell g_assert_not_reached(); 1006fb57878SPeter Maydell } 1016fb57878SPeter Maydell } 1026fb57878SPeter Maydell 1036fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) 1046fb57878SPeter Maydell { 1056fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1066fb57878SPeter Maydell 1076fb57878SPeter Maydell switch (size) { 1086fb57878SPeter Maydell case MO_8: 1096fb57878SPeter Maydell tcg_gen_st8_i64(var, cpu_env, offset); 1106fb57878SPeter Maydell break; 1116fb57878SPeter Maydell case MO_16: 1126fb57878SPeter Maydell tcg_gen_st16_i64(var, cpu_env, offset); 1136fb57878SPeter Maydell break; 1146fb57878SPeter Maydell case MO_32: 1156fb57878SPeter Maydell tcg_gen_st32_i64(var, cpu_env, offset); 1166fb57878SPeter Maydell break; 1176fb57878SPeter Maydell case MO_64: 1186fb57878SPeter Maydell tcg_gen_st_i64(var, cpu_env, offset); 1196fb57878SPeter Maydell break; 1206fb57878SPeter Maydell default: 1216fb57878SPeter Maydell g_assert_not_reached(); 1226fb57878SPeter Maydell } 1236fb57878SPeter Maydell } 1246fb57878SPeter Maydell 1255a46304cSRichard Henderson static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm, 1265a46304cSRichard Henderson int data, gen_helper_gvec_4 *fn_gvec) 1275a46304cSRichard Henderson { 1285a46304cSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 1295a46304cSRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 1305a46304cSRichard Henderson return false; 1315a46304cSRichard Henderson } 1325a46304cSRichard Henderson 1335a46304cSRichard Henderson /* 1345a46304cSRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 1355a46304cSRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 1365a46304cSRichard Henderson * when we have mixed Q- and D-reg inputs. 1375a46304cSRichard Henderson */ 1385a46304cSRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 1395a46304cSRichard Henderson return false; 1405a46304cSRichard Henderson } 1415a46304cSRichard Henderson 1425a46304cSRichard Henderson if (!vfp_access_check(s)) { 1435a46304cSRichard Henderson return true; 1445a46304cSRichard Henderson } 1455a46304cSRichard Henderson 1465a46304cSRichard Henderson int opr_sz = q ? 16 : 8; 1475a46304cSRichard Henderson tcg_gen_gvec_4_ool(vfp_reg_offset(1, vd), 1485a46304cSRichard Henderson vfp_reg_offset(1, vn), 1495a46304cSRichard Henderson vfp_reg_offset(1, vm), 1505a46304cSRichard Henderson vfp_reg_offset(1, vd), 1515a46304cSRichard Henderson opr_sz, opr_sz, data, fn_gvec); 1525a46304cSRichard Henderson return true; 1535a46304cSRichard Henderson } 1545a46304cSRichard Henderson 155505fce50SRichard Henderson static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, 156505fce50SRichard Henderson int data, ARMFPStatusFlavour fp_flavour, 157505fce50SRichard Henderson gen_helper_gvec_4_ptr *fn_gvec_ptr) 158afff8de0SPeter Maydell { 159afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 160505fce50SRichard Henderson if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { 161afff8de0SPeter Maydell return false; 162afff8de0SPeter Maydell } 163afff8de0SPeter Maydell 164505fce50SRichard Henderson /* 165505fce50SRichard Henderson * UNDEF accesses to odd registers for each bit of Q. 166505fce50SRichard Henderson * Q will be 0b111 for all Q-reg instructions, otherwise 167505fce50SRichard Henderson * when we have mixed Q- and D-reg inputs. 168505fce50SRichard Henderson */ 169505fce50SRichard Henderson if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) { 170afff8de0SPeter Maydell return false; 171afff8de0SPeter Maydell } 172afff8de0SPeter Maydell 173afff8de0SPeter Maydell if (!vfp_access_check(s)) { 174afff8de0SPeter Maydell return true; 175afff8de0SPeter Maydell } 176afff8de0SPeter Maydell 177505fce50SRichard Henderson int opr_sz = q ? 16 : 8; 178505fce50SRichard Henderson TCGv_ptr fpst = fpstatus_ptr(fp_flavour); 179505fce50SRichard Henderson 180505fce50SRichard Henderson tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd), 181505fce50SRichard Henderson vfp_reg_offset(1, vn), 182505fce50SRichard Henderson vfp_reg_offset(1, vm), 183505fce50SRichard Henderson vfp_reg_offset(1, vd), 184505fce50SRichard Henderson fpst, opr_sz, opr_sz, data, fn_gvec_ptr); 185afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 186afff8de0SPeter Maydell return true; 187afff8de0SPeter Maydell } 18894d5eb7bSPeter Maydell 189505fce50SRichard Henderson static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 190505fce50SRichard Henderson { 191505fce50SRichard Henderson if (!dc_isar_feature(aa32_vcma, s)) { 192505fce50SRichard Henderson return false; 193505fce50SRichard Henderson } 194505fce50SRichard Henderson if (a->size == MO_16) { 195505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 196505fce50SRichard Henderson return false; 197505fce50SRichard Henderson } 198505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 199505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah); 200505fce50SRichard Henderson } 201505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 7, a->vd, a->vn, a->vm, a->rot, 202505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas); 203505fce50SRichard Henderson } 204505fce50SRichard Henderson 20594d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 20694d5eb7bSPeter Maydell { 20794d5eb7bSPeter Maydell int opr_sz; 20894d5eb7bSPeter Maydell TCGv_ptr fpst; 20994d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 21094d5eb7bSPeter Maydell 21194d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 212d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 21394d5eb7bSPeter Maydell return false; 21494d5eb7bSPeter Maydell } 21594d5eb7bSPeter Maydell 21694d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 21794d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 21894d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 21994d5eb7bSPeter Maydell return false; 22094d5eb7bSPeter Maydell } 22194d5eb7bSPeter Maydell 22294d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 22394d5eb7bSPeter Maydell return false; 22494d5eb7bSPeter Maydell } 22594d5eb7bSPeter Maydell 22694d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 22794d5eb7bSPeter Maydell return true; 22894d5eb7bSPeter Maydell } 22994d5eb7bSPeter Maydell 23094d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 231d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 232d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 233d186a485SPeter Maydell gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds; 23494d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 23594d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 23694d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 23794d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 23894d5eb7bSPeter Maydell fn_gvec_ptr); 23994d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 24094d5eb7bSPeter Maydell return true; 24194d5eb7bSPeter Maydell } 24232da0e33SPeter Maydell 243f0ad96cbSRichard Henderson static bool trans_VSDOT(DisasContext *s, arg_VSDOT *a) 24432da0e33SPeter Maydell { 24532da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 24632da0e33SPeter Maydell return false; 24732da0e33SPeter Maydell } 2485a46304cSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 249f0ad96cbSRichard Henderson gen_helper_gvec_sdot_b); 250f0ad96cbSRichard Henderson } 251f0ad96cbSRichard Henderson 252f0ad96cbSRichard Henderson static bool trans_VUDOT(DisasContext *s, arg_VUDOT *a) 253f0ad96cbSRichard Henderson { 254f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 255f0ad96cbSRichard Henderson return false; 256f0ad96cbSRichard Henderson } 257f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 258f0ad96cbSRichard Henderson gen_helper_gvec_udot_b); 25932da0e33SPeter Maydell } 2609a107e7bSPeter Maydell 26151879c67SRichard Henderson static bool trans_VUSDOT(DisasContext *s, arg_VUSDOT *a) 26251879c67SRichard Henderson { 26351879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 26451879c67SRichard Henderson return false; 26551879c67SRichard Henderson } 26651879c67SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 26751879c67SRichard Henderson gen_helper_gvec_usdot_b); 26851879c67SRichard Henderson } 26951879c67SRichard Henderson 270cb8657f7SRichard Henderson static bool trans_VDOT_b16(DisasContext *s, arg_VDOT_b16 *a) 271cb8657f7SRichard Henderson { 272cb8657f7SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 273cb8657f7SRichard Henderson return false; 274cb8657f7SRichard Henderson } 275cb8657f7SRichard Henderson return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0, 276cb8657f7SRichard Henderson gen_helper_gvec_bfdot); 277cb8657f7SRichard Henderson } 278cb8657f7SRichard Henderson 2799a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 2809a107e7bSPeter Maydell { 2819a107e7bSPeter Maydell int opr_sz; 2829a107e7bSPeter Maydell 2839a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 2849a107e7bSPeter Maydell return false; 2859a107e7bSPeter Maydell } 2869a107e7bSPeter Maydell 2879a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2889a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2899a107e7bSPeter Maydell (a->vd & 0x10)) { 2909a107e7bSPeter Maydell return false; 2919a107e7bSPeter Maydell } 2929a107e7bSPeter Maydell 2939a107e7bSPeter Maydell if (a->vd & a->q) { 2949a107e7bSPeter Maydell return false; 2959a107e7bSPeter Maydell } 2969a107e7bSPeter Maydell 2979a107e7bSPeter Maydell if (!vfp_access_check(s)) { 2989a107e7bSPeter Maydell return true; 2999a107e7bSPeter Maydell } 3009a107e7bSPeter Maydell 3019a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 3029a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 3039a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 3049a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 3059a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 3069a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 3079a107e7bSPeter Maydell return true; 3089a107e7bSPeter Maydell } 3097e1b5d61SPeter Maydell 3107e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 3117e1b5d61SPeter Maydell { 312505fce50SRichard Henderson int data = (a->index << 2) | a->rot; 3137e1b5d61SPeter Maydell 3147e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 3157e1b5d61SPeter Maydell return false; 3167e1b5d61SPeter Maydell } 317505fce50SRichard Henderson if (a->size == MO_16) { 318505fce50SRichard Henderson if (!dc_isar_feature(aa32_fp16_arith, s)) { 3197e1b5d61SPeter Maydell return false; 3207e1b5d61SPeter Maydell } 321505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 322505fce50SRichard Henderson FPST_STD_F16, gen_helper_gvec_fcmlah_idx); 3237e1b5d61SPeter Maydell } 324505fce50SRichard Henderson return do_neon_ddda_fpst(s, a->q * 6, a->vd, a->vn, a->vm, data, 325505fce50SRichard Henderson FPST_STD, gen_helper_gvec_fcmlas_idx); 3267e1b5d61SPeter Maydell } 32735f5d4d1SPeter Maydell 328f0ad96cbSRichard Henderson static bool trans_VSDOT_scalar(DisasContext *s, arg_VSDOT_scalar *a) 32935f5d4d1SPeter Maydell { 33035f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 33135f5d4d1SPeter Maydell return false; 33235f5d4d1SPeter Maydell } 3335a46304cSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 334f0ad96cbSRichard Henderson gen_helper_gvec_sdot_idx_b); 335f0ad96cbSRichard Henderson } 336f0ad96cbSRichard Henderson 337f0ad96cbSRichard Henderson static bool trans_VUDOT_scalar(DisasContext *s, arg_VUDOT_scalar *a) 338f0ad96cbSRichard Henderson { 339f0ad96cbSRichard Henderson if (!dc_isar_feature(aa32_dp, s)) { 340f0ad96cbSRichard Henderson return false; 341f0ad96cbSRichard Henderson } 342f0ad96cbSRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 343f0ad96cbSRichard Henderson gen_helper_gvec_udot_idx_b); 34435f5d4d1SPeter Maydell } 345d27e82f7SPeter Maydell 34651879c67SRichard Henderson static bool trans_VUSDOT_scalar(DisasContext *s, arg_VUSDOT_scalar *a) 34751879c67SRichard Henderson { 34851879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 34951879c67SRichard Henderson return false; 35051879c67SRichard Henderson } 35151879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 35251879c67SRichard Henderson gen_helper_gvec_usdot_idx_b); 35351879c67SRichard Henderson } 35451879c67SRichard Henderson 35551879c67SRichard Henderson static bool trans_VSUDOT_scalar(DisasContext *s, arg_VSUDOT_scalar *a) 35651879c67SRichard Henderson { 35751879c67SRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 35851879c67SRichard Henderson return false; 35951879c67SRichard Henderson } 36051879c67SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 36151879c67SRichard Henderson gen_helper_gvec_sudot_idx_b); 36251879c67SRichard Henderson } 36351879c67SRichard Henderson 36483914478SRichard Henderson static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a) 36583914478SRichard Henderson { 36683914478SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 36783914478SRichard Henderson return false; 36883914478SRichard Henderson } 36983914478SRichard Henderson return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index, 37083914478SRichard Henderson gen_helper_gvec_bfdot_idx); 37183914478SRichard Henderson } 37283914478SRichard Henderson 373d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 374d27e82f7SPeter Maydell { 375d27e82f7SPeter Maydell int opr_sz; 376d27e82f7SPeter Maydell 377d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 378d27e82f7SPeter Maydell return false; 379d27e82f7SPeter Maydell } 380d27e82f7SPeter Maydell 381d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 382d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 383d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 384d27e82f7SPeter Maydell return false; 385d27e82f7SPeter Maydell } 386d27e82f7SPeter Maydell 387d27e82f7SPeter Maydell if (a->vd & a->q) { 388d27e82f7SPeter Maydell return false; 389d27e82f7SPeter Maydell } 390d27e82f7SPeter Maydell 391d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 392d27e82f7SPeter Maydell return true; 393d27e82f7SPeter Maydell } 394d27e82f7SPeter Maydell 395d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 396d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 397d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 398d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 399d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 400d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 401d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 402d27e82f7SPeter Maydell return true; 403d27e82f7SPeter Maydell } 404a27b4630SPeter Maydell 405a27b4630SPeter Maydell static struct { 406a27b4630SPeter Maydell int nregs; 407a27b4630SPeter Maydell int interleave; 408a27b4630SPeter Maydell int spacing; 409a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 410a27b4630SPeter Maydell {1, 4, 1}, 411a27b4630SPeter Maydell {1, 4, 2}, 412a27b4630SPeter Maydell {4, 1, 1}, 413a27b4630SPeter Maydell {2, 2, 2}, 414a27b4630SPeter Maydell {1, 3, 1}, 415a27b4630SPeter Maydell {1, 3, 2}, 416a27b4630SPeter Maydell {3, 1, 1}, 417a27b4630SPeter Maydell {1, 1, 1}, 418a27b4630SPeter Maydell {1, 2, 1}, 419a27b4630SPeter Maydell {1, 2, 2}, 420a27b4630SPeter Maydell {2, 1, 1} 421a27b4630SPeter Maydell }; 422a27b4630SPeter Maydell 423a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 424a27b4630SPeter Maydell int stride) 425a27b4630SPeter Maydell { 426a27b4630SPeter Maydell if (rm != 15) { 427a27b4630SPeter Maydell TCGv_i32 base; 428a27b4630SPeter Maydell 429a27b4630SPeter Maydell base = load_reg(s, rn); 430a27b4630SPeter Maydell if (rm == 13) { 431a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 432a27b4630SPeter Maydell } else { 433a27b4630SPeter Maydell TCGv_i32 index; 434a27b4630SPeter Maydell index = load_reg(s, rm); 435a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 436a27b4630SPeter Maydell tcg_temp_free_i32(index); 437a27b4630SPeter Maydell } 438a27b4630SPeter Maydell store_reg(s, rn, base); 439a27b4630SPeter Maydell } 440a27b4630SPeter Maydell } 441a27b4630SPeter Maydell 442a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 443a27b4630SPeter Maydell { 444a27b4630SPeter Maydell /* Neon load/store multiple structures */ 445a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 4467c68c196SRichard Henderson MemOp mop, align, endian; 447a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 448a27b4630SPeter Maydell int size = a->size; 449a27b4630SPeter Maydell TCGv_i64 tmp64; 450d9b47e97SRichard Henderson TCGv_i32 addr; 451a27b4630SPeter Maydell 452a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 453a27b4630SPeter Maydell return false; 454a27b4630SPeter Maydell } 455a27b4630SPeter Maydell 456a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 457a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 458a27b4630SPeter Maydell return false; 459a27b4630SPeter Maydell } 460a27b4630SPeter Maydell if (a->itype > 10) { 461a27b4630SPeter Maydell return false; 462a27b4630SPeter Maydell } 463a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 464a27b4630SPeter Maydell switch (a->itype & 0xc) { 465a27b4630SPeter Maydell case 4: 466a27b4630SPeter Maydell if (a->align >= 2) { 467a27b4630SPeter Maydell return false; 468a27b4630SPeter Maydell } 469a27b4630SPeter Maydell break; 470a27b4630SPeter Maydell case 8: 471a27b4630SPeter Maydell if (a->align == 3) { 472a27b4630SPeter Maydell return false; 473a27b4630SPeter Maydell } 474a27b4630SPeter Maydell break; 475a27b4630SPeter Maydell default: 476a27b4630SPeter Maydell break; 477a27b4630SPeter Maydell } 478a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 479a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 480a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 481a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 482a27b4630SPeter Maydell return false; 483a27b4630SPeter Maydell } 484a27b4630SPeter Maydell 485a27b4630SPeter Maydell if (!vfp_access_check(s)) { 486a27b4630SPeter Maydell return true; 487a27b4630SPeter Maydell } 488a27b4630SPeter Maydell 489a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 4907c68c196SRichard Henderson endian = s->be_data; 491a27b4630SPeter Maydell if (size == 0) { 492a27b4630SPeter Maydell endian = MO_LE; 493a27b4630SPeter Maydell } 4947c68c196SRichard Henderson 4957c68c196SRichard Henderson /* Enforce alignment requested by the instruction */ 4967c68c196SRichard Henderson if (a->align) { 4977c68c196SRichard Henderson align = pow2_align(a->align + 2); /* 4 ** a->align */ 4987c68c196SRichard Henderson } else { 4997c68c196SRichard Henderson align = s->align_mem ? MO_ALIGN : 0; 5007c68c196SRichard Henderson } 5017c68c196SRichard Henderson 502a27b4630SPeter Maydell /* 503a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 504a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 505a27b4630SPeter Maydell */ 506a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 5077c68c196SRichard Henderson /* Retain any natural alignment. */ 5087c68c196SRichard Henderson if (align == MO_ALIGN) { 5097c68c196SRichard Henderson align = pow2_align(size); 5107c68c196SRichard Henderson } 511a27b4630SPeter Maydell size = 3; 512a27b4630SPeter Maydell } 5137c68c196SRichard Henderson 514a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 515a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 516a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 5177c68c196SRichard Henderson 5187c68c196SRichard Henderson mop = endian | size | align; 519a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 520a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 521a27b4630SPeter Maydell int xs; 522a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 523a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 524a27b4630SPeter Maydell 525a27b4630SPeter Maydell if (a->l) { 5267c68c196SRichard Henderson gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop); 527a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 528a27b4630SPeter Maydell } else { 529a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 5307c68c196SRichard Henderson gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); 531a27b4630SPeter Maydell } 532d9b47e97SRichard Henderson tcg_gen_addi_i32(addr, addr, 1 << size); 5337c68c196SRichard Henderson 5347c68c196SRichard Henderson /* Subsequent memory operations inherit alignment */ 5357c68c196SRichard Henderson mop &= ~MO_AMASK; 536a27b4630SPeter Maydell } 537a27b4630SPeter Maydell } 538a27b4630SPeter Maydell } 539a27b4630SPeter Maydell tcg_temp_free_i32(addr); 540a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 541a27b4630SPeter Maydell 542a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 543a27b4630SPeter Maydell return true; 544a27b4630SPeter Maydell } 5453698747cSPeter Maydell 5463698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5473698747cSPeter Maydell { 5483698747cSPeter Maydell /* Neon load single structure to all lanes */ 5493698747cSPeter Maydell int reg, stride, vec_size; 5503698747cSPeter Maydell int vd = a->vd; 5513698747cSPeter Maydell int size = a->size; 5523698747cSPeter Maydell int nregs = a->n + 1; 5533698747cSPeter Maydell TCGv_i32 addr, tmp; 554a8502b37SRichard Henderson MemOp mop, align; 5553698747cSPeter Maydell 5563698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5573698747cSPeter Maydell return false; 5583698747cSPeter Maydell } 5593698747cSPeter Maydell 5603698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5613698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5623698747cSPeter Maydell return false; 5633698747cSPeter Maydell } 5643698747cSPeter Maydell 565a8502b37SRichard Henderson align = 0; 5663698747cSPeter Maydell if (size == 3) { 5673698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5683698747cSPeter Maydell return false; 5693698747cSPeter Maydell } 5703698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 571a8502b37SRichard Henderson size = MO_32; 572a8502b37SRichard Henderson align = MO_ALIGN_16; 573a8502b37SRichard Henderson } else if (a->a) { 574a8502b37SRichard Henderson switch (nregs) { 575a8502b37SRichard Henderson case 1: 576a8502b37SRichard Henderson if (size == 0) { 5773698747cSPeter Maydell return false; 5783698747cSPeter Maydell } 579a8502b37SRichard Henderson align = MO_ALIGN; 580a8502b37SRichard Henderson break; 581a8502b37SRichard Henderson case 2: 582a8502b37SRichard Henderson align = pow2_align(size + 1); 583a8502b37SRichard Henderson break; 584a8502b37SRichard Henderson case 3: 5853698747cSPeter Maydell return false; 586a8502b37SRichard Henderson case 4: 587*3a661024SClément Chigot if (size == 2) { 588*3a661024SClément Chigot align = pow2_align(3); 589*3a661024SClément Chigot } else { 590a8502b37SRichard Henderson align = pow2_align(size + 2); 591*3a661024SClément Chigot } 592a8502b37SRichard Henderson break; 593a8502b37SRichard Henderson default: 594a8502b37SRichard Henderson g_assert_not_reached(); 595a8502b37SRichard Henderson } 5963698747cSPeter Maydell } 5973698747cSPeter Maydell 5983698747cSPeter Maydell if (!vfp_access_check(s)) { 5993698747cSPeter Maydell return true; 6003698747cSPeter Maydell } 6013698747cSPeter Maydell 6023698747cSPeter Maydell /* 6033698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 6043698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 6053698747cSPeter Maydell */ 6063698747cSPeter Maydell stride = a->t ? 2 : 1; 6073698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 608a8502b37SRichard Henderson mop = size | align; 6093698747cSPeter Maydell tmp = tcg_temp_new_i32(); 6103698747cSPeter Maydell addr = tcg_temp_new_i32(); 6113698747cSPeter Maydell load_reg_var(s, addr, a->rn); 6123698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 613a8502b37SRichard Henderson gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); 6143698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 6153698747cSPeter Maydell /* 6163698747cSPeter Maydell * We cannot write 16 bytes at once because the 6173698747cSPeter Maydell * destination is unaligned. 6183698747cSPeter Maydell */ 619015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6203698747cSPeter Maydell 8, 8, tmp); 621015ee81aSRichard Henderson tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1), 622015ee81aSRichard Henderson neon_full_reg_offset(vd), 8, 8); 6233698747cSPeter Maydell } else { 624015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 6253698747cSPeter Maydell vec_size, vec_size, tmp); 6263698747cSPeter Maydell } 6273698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 6283698747cSPeter Maydell vd += stride; 629a8502b37SRichard Henderson 630a8502b37SRichard Henderson /* Subsequent memory operations inherit alignment */ 631a8502b37SRichard Henderson mop &= ~MO_AMASK; 6323698747cSPeter Maydell } 6333698747cSPeter Maydell tcg_temp_free_i32(tmp); 6343698747cSPeter Maydell tcg_temp_free_i32(addr); 6353698747cSPeter Maydell 6363698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 6373698747cSPeter Maydell 6383698747cSPeter Maydell return true; 6393698747cSPeter Maydell } 640123ce4e3SPeter Maydell 641123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 642123ce4e3SPeter Maydell { 643123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 644123ce4e3SPeter Maydell int reg; 645123ce4e3SPeter Maydell int nregs = a->n + 1; 646123ce4e3SPeter Maydell int vd = a->vd; 647123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 64888976ff0SRichard Henderson MemOp mop; 649123ce4e3SPeter Maydell 650123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 651123ce4e3SPeter Maydell return false; 652123ce4e3SPeter Maydell } 653123ce4e3SPeter Maydell 654123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 655123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 656123ce4e3SPeter Maydell return false; 657123ce4e3SPeter Maydell } 658123ce4e3SPeter Maydell 659123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 660123ce4e3SPeter Maydell switch (nregs) { 661123ce4e3SPeter Maydell case 1: 662c64ee036SPeter Maydell if (a->stride != 1) { 663c64ee036SPeter Maydell return false; 664c64ee036SPeter Maydell } 665123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 666a736cbc3SRichard Henderson (a->size == 2 && (a->align == 1 || a->align == 2))) { 667123ce4e3SPeter Maydell return false; 668123ce4e3SPeter Maydell } 669123ce4e3SPeter Maydell break; 670123ce4e3SPeter Maydell case 2: 671123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 672123ce4e3SPeter Maydell return false; 673123ce4e3SPeter Maydell } 674123ce4e3SPeter Maydell break; 67541c5a0f7SPeter Maydell case 3: 67641c5a0f7SPeter Maydell if (a->align != 0) { 67741c5a0f7SPeter Maydell return false; 67841c5a0f7SPeter Maydell } 67941c5a0f7SPeter Maydell break; 680123ce4e3SPeter Maydell case 4: 681a736cbc3SRichard Henderson if (a->size == 2 && a->align == 3) { 682123ce4e3SPeter Maydell return false; 683123ce4e3SPeter Maydell } 684123ce4e3SPeter Maydell break; 685123ce4e3SPeter Maydell default: 686d385a605SRichard Henderson g_assert_not_reached(); 687123ce4e3SPeter Maydell } 688123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 689123ce4e3SPeter Maydell /* 690123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 691123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 692123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 693123ce4e3SPeter Maydell */ 694123ce4e3SPeter Maydell return false; 695123ce4e3SPeter Maydell } 696123ce4e3SPeter Maydell 697123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 698123ce4e3SPeter Maydell return true; 699123ce4e3SPeter Maydell } 700123ce4e3SPeter Maydell 70188976ff0SRichard Henderson /* Pick up SCTLR settings */ 70288976ff0SRichard Henderson mop = finalize_memop(s, a->size); 70388976ff0SRichard Henderson 70488976ff0SRichard Henderson if (a->align) { 70588976ff0SRichard Henderson MemOp align_op; 70688976ff0SRichard Henderson 70788976ff0SRichard Henderson switch (nregs) { 70888976ff0SRichard Henderson case 1: 70988976ff0SRichard Henderson /* For VLD1, use natural alignment. */ 71088976ff0SRichard Henderson align_op = MO_ALIGN; 71188976ff0SRichard Henderson break; 71288976ff0SRichard Henderson case 2: 71388976ff0SRichard Henderson /* For VLD2, use double alignment. */ 71488976ff0SRichard Henderson align_op = pow2_align(a->size + 1); 71588976ff0SRichard Henderson break; 71688976ff0SRichard Henderson case 4: 71788976ff0SRichard Henderson if (a->size == MO_32) { 71888976ff0SRichard Henderson /* 71988976ff0SRichard Henderson * For VLD4.32, align = 1 is double alignment, align = 2 is 72088976ff0SRichard Henderson * quad alignment; align = 3 is rejected above. 72188976ff0SRichard Henderson */ 72288976ff0SRichard Henderson align_op = pow2_align(a->size + a->align); 72388976ff0SRichard Henderson } else { 72488976ff0SRichard Henderson /* For VLD4.8 and VLD.16, we want quad alignment. */ 72588976ff0SRichard Henderson align_op = pow2_align(a->size + 2); 72688976ff0SRichard Henderson } 72788976ff0SRichard Henderson break; 72888976ff0SRichard Henderson default: 72988976ff0SRichard Henderson /* For VLD3, the alignment field is zero and rejected above. */ 73088976ff0SRichard Henderson g_assert_not_reached(); 73188976ff0SRichard Henderson } 73288976ff0SRichard Henderson 73388976ff0SRichard Henderson mop = (mop & ~MO_AMASK) | align_op; 73488976ff0SRichard Henderson } 73588976ff0SRichard Henderson 736123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 737123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 738123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 73988976ff0SRichard Henderson 740123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 741123ce4e3SPeter Maydell if (a->l) { 74288976ff0SRichard Henderson gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop); 743123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 744123ce4e3SPeter Maydell } else { /* Store */ 745123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 74688976ff0SRichard Henderson gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop); 747123ce4e3SPeter Maydell } 748123ce4e3SPeter Maydell vd += a->stride; 749123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 75088976ff0SRichard Henderson 75188976ff0SRichard Henderson /* Subsequent memory operations inherit alignment */ 75288976ff0SRichard Henderson mop &= ~MO_AMASK; 753123ce4e3SPeter Maydell } 754123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 755123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 756123ce4e3SPeter Maydell 757123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 758123ce4e3SPeter Maydell 759123ce4e3SPeter Maydell return true; 760123ce4e3SPeter Maydell } 761a4e143acSPeter Maydell 762a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 763a4e143acSPeter Maydell { 764a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 765015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 766015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 767015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 768a4e143acSPeter Maydell 769a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 770a4e143acSPeter Maydell return false; 771a4e143acSPeter Maydell } 772a4e143acSPeter Maydell 773a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 774a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 775a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 776a4e143acSPeter Maydell return false; 777a4e143acSPeter Maydell } 778a4e143acSPeter Maydell 779a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 780a4e143acSPeter Maydell return false; 781a4e143acSPeter Maydell } 782a4e143acSPeter Maydell 783a4e143acSPeter Maydell if (!vfp_access_check(s)) { 784a4e143acSPeter Maydell return true; 785a4e143acSPeter Maydell } 786a4e143acSPeter Maydell 787a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 788a4e143acSPeter Maydell return true; 789a4e143acSPeter Maydell } 790a4e143acSPeter Maydell 791a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 792a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 793a4e143acSPeter Maydell { \ 794a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 795a4e143acSPeter Maydell } 796a4e143acSPeter Maydell 797a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 798a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 79935a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 80035a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 80135a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 80235a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 80335a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 8048161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 8058161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 806c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 807c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 808c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 809c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 81035a548edSPeter Maydell 81135a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 81235a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 81335a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 81435a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 81535a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 81635a548edSPeter Maydell { \ 81735a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 81835a548edSPeter Maydell } \ 81935a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 82035a548edSPeter Maydell 82135a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 82235a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 82335a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 82436b59310SPeter Maydell 82536b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 82636b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 82736b59310SPeter Maydell { \ 82836b59310SPeter Maydell if (a->size == 3) { \ 82936b59310SPeter Maydell return false; \ 83036b59310SPeter Maydell } \ 83136b59310SPeter Maydell return do_3same(s, a, FUNC); \ 83236b59310SPeter Maydell } 83336b59310SPeter Maydell 83436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 83536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 83636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 83736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 8380de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 83927106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 84027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 8418161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 8427715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 8437715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 8447715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 8457715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 84602bd0cdbSPeter Maydell 84702bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 84802bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 84902bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 85002bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 85102bd0cdbSPeter Maydell { \ 85202bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 85302bd0cdbSPeter Maydell } \ 85402bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 85502bd0cdbSPeter Maydell 85602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 85702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 85802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 85902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 86002bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 86102bd0cdbSPeter Maydell 862effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 863effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 864effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 865effa992fSRichard Henderson { \ 866effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 8670de34fd4SPeter Maydell } 8680de34fd4SPeter Maydell 869effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 870effa992fSRichard Henderson 8710de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 8720de34fd4SPeter Maydell { 8730de34fd4SPeter Maydell if (a->size != 0) { 8740de34fd4SPeter Maydell return false; 8750de34fd4SPeter Maydell } 8760de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 8770de34fd4SPeter Maydell } 878a0635695SPeter Maydell 879a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 880a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 881a0635695SPeter Maydell { \ 882a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 883a0635695SPeter Maydell return false; \ 884a0635695SPeter Maydell } \ 885a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 886a0635695SPeter Maydell return false; \ 887a0635695SPeter Maydell } \ 888a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 889a0635695SPeter Maydell } 890a0635695SPeter Maydell 891a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 892a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 89321290edfSPeter Maydell 894afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 895afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 896afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 897afc8b7d3SRichard Henderson { \ 898afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 899afc8b7d3SRichard Henderson return false; \ 900afc8b7d3SRichard Henderson } \ 901afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 90221290edfSPeter Maydell } 90321290edfSPeter Maydell 904afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 905afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 906afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 907afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 90821290edfSPeter Maydell 909effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 910effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 911effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 912effa992fSRichard Henderson { \ 913effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 914effa992fSRichard Henderson return false; \ 915effa992fSRichard Henderson } \ 916effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 91721290edfSPeter Maydell } 91821290edfSPeter Maydell 919effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 920effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 921effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 92235d4352fSPeter Maydell 92335d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 92435d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 92535d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 92635d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 92735d4352fSPeter Maydell { \ 92835d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 92935d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 93035d4352fSPeter Maydell } \ 93135d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 93235d4352fSPeter Maydell 93335d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 93435d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 93535d4352fSPeter Maydell { \ 93635d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 93735d4352fSPeter Maydell } \ 93835d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 93935d4352fSPeter Maydell 94035d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 94135d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 94235d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 94335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 94435d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 94535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 946cb294bcaSPeter Maydell 947cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 948cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 949cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 950cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 951cb294bcaSPeter Maydell { \ 952cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 953cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 954cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 955cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 956cb294bcaSPeter Maydell { 0 }, \ 957cb294bcaSPeter Maydell }; \ 958cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 959cb294bcaSPeter Maydell } \ 960cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 961cb294bcaSPeter Maydell { \ 962cb294bcaSPeter Maydell if (a->size > 2) { \ 963cb294bcaSPeter Maydell return false; \ 964cb294bcaSPeter Maydell } \ 965cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 966cb294bcaSPeter Maydell } 967cb294bcaSPeter Maydell 9686812dfdcSPeter Maydell /* 9696812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 9706812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 9716812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 9726812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 9736812dfdcSPeter Maydell */ 9746812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 9756812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 9766812dfdcSPeter Maydell { \ 9776812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 9786812dfdcSPeter Maydell } 9796812dfdcSPeter Maydell 9806812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 9816812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 9826812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 9836812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 9846812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9856812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9866812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9876812dfdcSPeter Maydell { \ 9886812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 9896812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9906812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9916812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9926812dfdcSPeter Maydell { 0 }, \ 9936812dfdcSPeter Maydell }; \ 9946812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 9956812dfdcSPeter Maydell } \ 9966812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9976812dfdcSPeter Maydell { \ 9986812dfdcSPeter Maydell if (a->size > 2) { \ 9996812dfdcSPeter Maydell return false; \ 10006812dfdcSPeter Maydell } \ 10016812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 10026812dfdcSPeter Maydell } 10036812dfdcSPeter Maydell 1004cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 1005cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 10068e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 10078e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 10088e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 10098e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 10106812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 10116812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 10126812dfdcSPeter Maydell 10136812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 10146812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 10156812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 10166812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 1017059c2398SPeter Maydell 1018059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 1019059c2398SPeter Maydell { 1020059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 1021059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1022059c2398SPeter Maydell 1023059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1024059c2398SPeter Maydell return false; 1025059c2398SPeter Maydell } 1026059c2398SPeter Maydell 1027059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1028059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1029059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1030059c2398SPeter Maydell return false; 1031059c2398SPeter Maydell } 1032059c2398SPeter Maydell 1033059c2398SPeter Maydell if (a->size == 3) { 1034059c2398SPeter Maydell return false; 1035059c2398SPeter Maydell } 1036059c2398SPeter Maydell 1037059c2398SPeter Maydell if (!vfp_access_check(s)) { 1038059c2398SPeter Maydell return true; 1039059c2398SPeter Maydell } 1040059c2398SPeter Maydell 1041059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1042059c2398SPeter Maydell 1043059c2398SPeter Maydell /* 1044059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 1045059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1046059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1047059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 1048059c2398SPeter Maydell */ 1049a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 1050a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 1051a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 1052a712266fSRichard Henderson 1053a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1054a712266fSRichard Henderson read_neon_element32(tmp2, a->vn, 1, MO_32); 1055059c2398SPeter Maydell fn(tmp, tmp, tmp2); 1056059c2398SPeter Maydell 1057a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 0, MO_32); 1058a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 1059059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 1060059c2398SPeter Maydell 1061a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 0, MO_32); 1062a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 1063a712266fSRichard Henderson 1064a712266fSRichard Henderson tcg_temp_free_i32(tmp); 1065a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 1066a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 1067059c2398SPeter Maydell return true; 1068059c2398SPeter Maydell } 1069059c2398SPeter Maydell 1070059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 1071059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 1072059c2398SPeter Maydell { \ 1073059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 1074059c2398SPeter Maydell gen_helper_neon_##func##8, \ 1075059c2398SPeter Maydell gen_helper_neon_##func##16, \ 1076059c2398SPeter Maydell gen_helper_neon_##func##32, \ 1077059c2398SPeter Maydell }; \ 1078059c2398SPeter Maydell if (a->size > 2) { \ 1079059c2398SPeter Maydell return false; \ 1080059c2398SPeter Maydell } \ 1081059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 1082059c2398SPeter Maydell } 1083059c2398SPeter Maydell 1084059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 1085059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 1086059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 1087059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 1088059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 1089fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1090059c2398SPeter Maydell 1091059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1092059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1093059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1094059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1095fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 10967ecc28bcSPeter Maydell 10977ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 10987ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 10997ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 11007ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 11017ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 11027ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 11037ecc28bcSPeter Maydell { \ 11047ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 11057ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 11067ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 11077ecc28bcSPeter Maydell }; \ 11087ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 11097ecc28bcSPeter Maydell } \ 11107ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 11117ecc28bcSPeter Maydell { \ 11127ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 11137ecc28bcSPeter Maydell return false; \ 11147ecc28bcSPeter Maydell } \ 11157ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 11167ecc28bcSPeter Maydell } 11177ecc28bcSPeter Maydell 11187ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 11197ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1120a26a352bSPeter Maydell 1121e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1122e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1123a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1124a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1125a26a352bSPeter Maydell { \ 1126e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1127a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1128a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1129a26a352bSPeter Maydell tcg_temp_free_ptr(fpst); \ 1130e4a6d4a6SPeter Maydell } 1131e4a6d4a6SPeter Maydell 1132e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1133e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1134e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1135a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1136a26a352bSPeter Maydell { \ 11376cf0f240SPeter Maydell if (a->size == MO_16) { \ 1138e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1139a26a352bSPeter Maydell return false; \ 1140a26a352bSPeter Maydell } \ 1141e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1142e4a6d4a6SPeter Maydell } \ 1143e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1144a26a352bSPeter Maydell } 1145a26a352bSPeter Maydell 1146a26a352bSPeter Maydell 1147e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1148e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1149e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1150e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 1151ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h) 1152ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h) 1153ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h) 1154bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h) 1155bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h) 1156e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h) 1157e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h) 1158e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h) 1159e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h) 1160cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h) 1161cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h) 1162ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h) 116340fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h) 1164ab978335SPeter Maydell 1165e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s) 1166e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h) 1167e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s) 1168e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h) 1169e22705bbSPeter Maydell 1170d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1171d5fdf9e9SPeter Maydell { 1172d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1173d5fdf9e9SPeter Maydell return false; 1174d5fdf9e9SPeter Maydell } 1175d5fdf9e9SPeter Maydell 11766cf0f240SPeter Maydell if (a->size == MO_16) { 1177e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1178d5fdf9e9SPeter Maydell return false; 1179d5fdf9e9SPeter Maydell } 1180e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp16_3s); 1181e22705bbSPeter Maydell } 1182e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp32_3s); 1183d5fdf9e9SPeter Maydell } 1184d5fdf9e9SPeter Maydell 1185d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1186d5fdf9e9SPeter Maydell { 1187d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1188d5fdf9e9SPeter Maydell return false; 1189d5fdf9e9SPeter Maydell } 1190d5fdf9e9SPeter Maydell 11916cf0f240SPeter Maydell if (a->size == MO_16) { 1192e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1193d5fdf9e9SPeter Maydell return false; 1194d5fdf9e9SPeter Maydell } 1195e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp16_3s); 1196e22705bbSPeter Maydell } 1197e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp32_3s); 1198d5fdf9e9SPeter Maydell } 1199d5fdf9e9SPeter Maydell 12001dc587eeSPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, 12011dc587eeSPeter Maydell gen_helper_gvec_3_ptr *fn) 1202ab978335SPeter Maydell { 12031dc587eeSPeter Maydell /* FP pairwise operations */ 1204ab978335SPeter Maydell TCGv_ptr fpstatus; 1205ab978335SPeter Maydell 1206ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1207ab978335SPeter Maydell return false; 1208ab978335SPeter Maydell } 1209ab978335SPeter Maydell 1210ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1211ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1212ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1213ab978335SPeter Maydell return false; 1214ab978335SPeter Maydell } 1215ab978335SPeter Maydell 1216ab978335SPeter Maydell if (!vfp_access_check(s)) { 1217ab978335SPeter Maydell return true; 1218ab978335SPeter Maydell } 1219ab978335SPeter Maydell 1220ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1221ab978335SPeter Maydell 1222ab978335SPeter Maydell 12236cf0f240SPeter Maydell fpstatus = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 12241dc587eeSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 12251dc587eeSPeter Maydell vfp_reg_offset(1, a->vn), 12261dc587eeSPeter Maydell vfp_reg_offset(1, a->vm), 12271dc587eeSPeter Maydell fpstatus, 8, 8, 0, fn); 1228ab978335SPeter Maydell tcg_temp_free_ptr(fpstatus); 1229ab978335SPeter Maydell 1230ab978335SPeter Maydell return true; 1231ab978335SPeter Maydell } 1232ab978335SPeter Maydell 1233ab978335SPeter Maydell /* 1234ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1235ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1236ab978335SPeter Maydell */ 1237ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1238ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1239ab978335SPeter Maydell { \ 12406cf0f240SPeter Maydell if (a->size == MO_16) { \ 12411dc587eeSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1242ab978335SPeter Maydell return false; \ 1243ab978335SPeter Maydell } \ 12441dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##h); \ 12451dc587eeSPeter Maydell } \ 12461dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##s); \ 1247ab978335SPeter Maydell } 1248ab978335SPeter Maydell 12491dc587eeSPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_neon_padd) 12501dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_neon_pmax) 12511dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_neon_pmin) 1252d3c8c736SPeter Maydell 1253d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1254d3c8c736SPeter Maydell { 1255d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1256d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1257015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1258015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 1259d3c8c736SPeter Maydell 1260d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1261d3c8c736SPeter Maydell return false; 1262d3c8c736SPeter Maydell } 1263d3c8c736SPeter Maydell 1264d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1265d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1266d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1267d3c8c736SPeter Maydell return false; 1268d3c8c736SPeter Maydell } 1269d3c8c736SPeter Maydell 1270d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1271d3c8c736SPeter Maydell return false; 1272d3c8c736SPeter Maydell } 1273d3c8c736SPeter Maydell 1274d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1275d3c8c736SPeter Maydell return true; 1276d3c8c736SPeter Maydell } 1277d3c8c736SPeter Maydell 1278d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1279d3c8c736SPeter Maydell return true; 1280d3c8c736SPeter Maydell } 1281d3c8c736SPeter Maydell 1282d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1283d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1284d3c8c736SPeter Maydell { \ 1285d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1286d3c8c736SPeter Maydell } \ 1287d3c8c736SPeter Maydell 1288d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1289d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1290434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1291434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1292434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1293434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1294434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1295434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1296434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 129766432d6bSPeter Maydell 129866432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 129966432d6bSPeter Maydell { 130066432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 130166432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 130266432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 130366432d6bSPeter Maydell } 130466432d6bSPeter Maydell 130566432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 130666432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 130766432d6bSPeter Maydell { 130866432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 130966432d6bSPeter Maydell } 131066432d6bSPeter Maydell 131166432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 131266432d6bSPeter Maydell { 131366432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 131466432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 131566432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 131666432d6bSPeter Maydell } else { 131766432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 131866432d6bSPeter Maydell } 131966432d6bSPeter Maydell } 132037bfce81SPeter Maydell 132137bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 132237bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 132337bfce81SPeter Maydell { 132437bfce81SPeter Maydell /* 132537bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 132637bfce81SPeter Maydell * function needs to be passed cpu_env. 132737bfce81SPeter Maydell */ 132837bfce81SPeter Maydell TCGv_i64 constimm; 132937bfce81SPeter Maydell int pass; 133037bfce81SPeter Maydell 133137bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 133237bfce81SPeter Maydell return false; 133337bfce81SPeter Maydell } 133437bfce81SPeter Maydell 133537bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 133637bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 133737bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 133837bfce81SPeter Maydell return false; 133937bfce81SPeter Maydell } 134037bfce81SPeter Maydell 134137bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 134237bfce81SPeter Maydell return false; 134337bfce81SPeter Maydell } 134437bfce81SPeter Maydell 134537bfce81SPeter Maydell if (!vfp_access_check(s)) { 134637bfce81SPeter Maydell return true; 134737bfce81SPeter Maydell } 134837bfce81SPeter Maydell 134937bfce81SPeter Maydell /* 135037bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 135137bfce81SPeter Maydell * by immediate using the variable shift operations. 135237bfce81SPeter Maydell */ 1353d9b47e97SRichard Henderson constimm = tcg_constant_i64(dup_const(a->size, a->shift)); 135437bfce81SPeter Maydell 135537bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 135637bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 135737bfce81SPeter Maydell 13580aa8e700SRichard Henderson read_neon_element64(tmp, a->vm, pass, MO_64); 135937bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 13600aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, pass, MO_64); 1361a4f67e18SPeter Maydell tcg_temp_free_i64(tmp); 136237bfce81SPeter Maydell } 136337bfce81SPeter Maydell return true; 136437bfce81SPeter Maydell } 136537bfce81SPeter Maydell 136637bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 136737bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 136837bfce81SPeter Maydell { 136937bfce81SPeter Maydell /* 137037bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 137137bfce81SPeter Maydell * helper needs to be passed cpu_env. 137237bfce81SPeter Maydell */ 1373a712266fSRichard Henderson TCGv_i32 constimm, tmp; 137437bfce81SPeter Maydell int pass; 137537bfce81SPeter Maydell 137637bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 137737bfce81SPeter Maydell return false; 137837bfce81SPeter Maydell } 137937bfce81SPeter Maydell 138037bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 138137bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 138237bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 138337bfce81SPeter Maydell return false; 138437bfce81SPeter Maydell } 138537bfce81SPeter Maydell 138637bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 138737bfce81SPeter Maydell return false; 138837bfce81SPeter Maydell } 138937bfce81SPeter Maydell 139037bfce81SPeter Maydell if (!vfp_access_check(s)) { 139137bfce81SPeter Maydell return true; 139237bfce81SPeter Maydell } 139337bfce81SPeter Maydell 139437bfce81SPeter Maydell /* 139537bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 139637bfce81SPeter Maydell * by immediate using the variable shift operations. 139737bfce81SPeter Maydell */ 1398d9b47e97SRichard Henderson constimm = tcg_constant_i32(dup_const(a->size, a->shift)); 1399a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 140037bfce81SPeter Maydell 140137bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 1402a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 140337bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 1404a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 140537bfce81SPeter Maydell } 1406a712266fSRichard Henderson tcg_temp_free_i32(tmp); 140737bfce81SPeter Maydell return true; 140837bfce81SPeter Maydell } 140937bfce81SPeter Maydell 141037bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 141137bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 141237bfce81SPeter Maydell { \ 141337bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 141437bfce81SPeter Maydell } \ 141537bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 141637bfce81SPeter Maydell { \ 141737bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 141837bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 141937bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 142037bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 142137bfce81SPeter Maydell }; \ 142237bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 142337bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 142437bfce81SPeter Maydell } 142537bfce81SPeter Maydell 142637bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 142737bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 142837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1429712182d3SPeter Maydell 1430712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1431712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1432712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1433712182d3SPeter Maydell { 1434712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1435712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1436712182d3SPeter Maydell TCGv_i32 rd; 1437712182d3SPeter Maydell 1438712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1439712182d3SPeter Maydell return false; 1440712182d3SPeter Maydell } 1441712182d3SPeter Maydell 1442712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1443712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1444712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1445712182d3SPeter Maydell return false; 1446712182d3SPeter Maydell } 1447712182d3SPeter Maydell 1448712182d3SPeter Maydell if (a->vm & 1) { 1449712182d3SPeter Maydell return false; 1450712182d3SPeter Maydell } 1451712182d3SPeter Maydell 1452712182d3SPeter Maydell if (!vfp_access_check(s)) { 1453712182d3SPeter Maydell return true; 1454712182d3SPeter Maydell } 1455712182d3SPeter Maydell 1456712182d3SPeter Maydell /* 1457712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1458712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1459712182d3SPeter Maydell */ 1460d9b47e97SRichard Henderson constimm = tcg_constant_i64(-a->shift); 1461712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1462712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1463a712266fSRichard Henderson rd = tcg_temp_new_i32(); 1464712182d3SPeter Maydell 1465712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 14660aa8e700SRichard Henderson read_neon_element64(rm1, a->vm, 0, MO_64); 14670aa8e700SRichard Henderson read_neon_element64(rm2, a->vm, 1, MO_64); 1468712182d3SPeter Maydell 1469712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1470712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1471a712266fSRichard Henderson write_neon_element32(rd, a->vd, 0, MO_32); 1472712182d3SPeter Maydell 1473712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1474712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1475a712266fSRichard Henderson write_neon_element32(rd, a->vd, 1, MO_32); 1476712182d3SPeter Maydell 1477a712266fSRichard Henderson tcg_temp_free_i32(rd); 1478712182d3SPeter Maydell tcg_temp_free_i64(rm1); 1479712182d3SPeter Maydell tcg_temp_free_i64(rm2); 1480712182d3SPeter Maydell 1481712182d3SPeter Maydell return true; 1482712182d3SPeter Maydell } 1483712182d3SPeter Maydell 1484712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1485712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1486712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1487712182d3SPeter Maydell { 1488712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1489712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1490712182d3SPeter Maydell TCGv_i64 rtmp; 1491712182d3SPeter Maydell uint32_t imm; 1492712182d3SPeter Maydell 1493712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1494712182d3SPeter Maydell return false; 1495712182d3SPeter Maydell } 1496712182d3SPeter Maydell 1497712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1498712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1499712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1500712182d3SPeter Maydell return false; 1501712182d3SPeter Maydell } 1502712182d3SPeter Maydell 1503712182d3SPeter Maydell if (a->vm & 1) { 1504712182d3SPeter Maydell return false; 1505712182d3SPeter Maydell } 1506712182d3SPeter Maydell 1507712182d3SPeter Maydell if (!vfp_access_check(s)) { 1508712182d3SPeter Maydell return true; 1509712182d3SPeter Maydell } 1510712182d3SPeter Maydell 1511712182d3SPeter Maydell /* 1512712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1513712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1514712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1515712182d3SPeter Maydell */ 1516712182d3SPeter Maydell if (a->size == 1) { 1517712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1518712182d3SPeter Maydell imm |= imm << 16; 1519712182d3SPeter Maydell } else { 1520712182d3SPeter Maydell /* size == 2 */ 1521712182d3SPeter Maydell imm = -a->shift; 1522712182d3SPeter Maydell } 1523d9b47e97SRichard Henderson constimm = tcg_constant_i32(imm); 1524712182d3SPeter Maydell 1525712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1526a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1527a712266fSRichard Henderson rm2 = tcg_temp_new_i32(); 1528a712266fSRichard Henderson rm3 = tcg_temp_new_i32(); 1529a712266fSRichard Henderson rm4 = tcg_temp_new_i32(); 1530a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 0, MO_32); 1531a712266fSRichard Henderson read_neon_element32(rm2, a->vm, 1, MO_32); 1532a712266fSRichard Henderson read_neon_element32(rm3, a->vm, 2, MO_32); 1533a712266fSRichard Henderson read_neon_element32(rm4, a->vm, 3, MO_32); 1534712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1535712182d3SPeter Maydell 1536712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1537712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1538712182d3SPeter Maydell 1539712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1540712182d3SPeter Maydell tcg_temp_free_i32(rm2); 1541712182d3SPeter Maydell 1542712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1543a712266fSRichard Henderson write_neon_element32(rm1, a->vd, 0, MO_32); 1544a712266fSRichard Henderson tcg_temp_free_i32(rm1); 1545712182d3SPeter Maydell 1546712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1547712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1548712182d3SPeter Maydell 1549712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1550712182d3SPeter Maydell tcg_temp_free_i32(rm4); 1551712182d3SPeter Maydell 1552712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1553712182d3SPeter Maydell tcg_temp_free_i64(rtmp); 1554a712266fSRichard Henderson write_neon_element32(rm3, a->vd, 1, MO_32); 1555a712266fSRichard Henderson tcg_temp_free_i32(rm3); 1556712182d3SPeter Maydell return true; 1557712182d3SPeter Maydell } 1558712182d3SPeter Maydell 1559712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1560712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1561712182d3SPeter Maydell { \ 1562712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1563712182d3SPeter Maydell } 1564712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1565712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1566712182d3SPeter Maydell { \ 1567712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1568712182d3SPeter Maydell } 1569712182d3SPeter Maydell 1570712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1571712182d3SPeter Maydell { 1572712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1573712182d3SPeter Maydell } 1574712182d3SPeter Maydell 1575712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1576712182d3SPeter Maydell { 1577712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1578712182d3SPeter Maydell } 1579712182d3SPeter Maydell 1580712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1581712182d3SPeter Maydell { 1582712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1583712182d3SPeter Maydell } 1584712182d3SPeter Maydell 1585712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1586712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1587712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1588712182d3SPeter Maydell 1589712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1590712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1591712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1592712182d3SPeter Maydell 1593712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1594712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1595712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1596712182d3SPeter Maydell 1597712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1598712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1599712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1600b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1601b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1602b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1603b4a3a77bSPeter Maydell 1604b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1605b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1606b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1607b4a3a77bSPeter Maydell 1608b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1609b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1610b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1611b4a3a77bSPeter Maydell 1612b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1613b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1614b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1615968bf842SPeter Maydell 1616968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1617968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1618968bf842SPeter Maydell { 1619968bf842SPeter Maydell TCGv_i64 tmp; 1620968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1621968bf842SPeter Maydell uint64_t widen_mask = 0; 1622968bf842SPeter Maydell 1623968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1624968bf842SPeter Maydell return false; 1625968bf842SPeter Maydell } 1626968bf842SPeter Maydell 1627968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1628968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1629968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1630968bf842SPeter Maydell return false; 1631968bf842SPeter Maydell } 1632968bf842SPeter Maydell 1633968bf842SPeter Maydell if (a->vd & 1) { 1634968bf842SPeter Maydell return false; 1635968bf842SPeter Maydell } 1636968bf842SPeter Maydell 1637968bf842SPeter Maydell if (!vfp_access_check(s)) { 1638968bf842SPeter Maydell return true; 1639968bf842SPeter Maydell } 1640968bf842SPeter Maydell 1641968bf842SPeter Maydell /* 1642968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1643968bf842SPeter Maydell * than the width of the source type, so after widening the input 1644968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1645968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1646968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1647968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1648968bf842SPeter Maydell */ 1649968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1650968bf842SPeter Maydell int esize = 8 << a->size; 1651968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1652968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1653968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1654968bf842SPeter Maydell } 1655968bf842SPeter Maydell 1656a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 1657a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1658a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 1659a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 1660968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1661968bf842SPeter Maydell 1662968bf842SPeter Maydell widenfn(tmp, rm0); 16639593a398SPeter Maydell tcg_temp_free_i32(rm0); 1664968bf842SPeter Maydell if (a->shift != 0) { 1665968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1666968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1667968bf842SPeter Maydell } 16680aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 0, MO_64); 1669968bf842SPeter Maydell 1670968bf842SPeter Maydell widenfn(tmp, rm1); 16719593a398SPeter Maydell tcg_temp_free_i32(rm1); 1672968bf842SPeter Maydell if (a->shift != 0) { 1673968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1674968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1675968bf842SPeter Maydell } 16760aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 1, MO_64); 1677968bf842SPeter Maydell tcg_temp_free_i64(tmp); 1678968bf842SPeter Maydell return true; 1679968bf842SPeter Maydell } 1680968bf842SPeter Maydell 1681968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1682968bf842SPeter Maydell { 1683448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1684968bf842SPeter Maydell gen_helper_neon_widen_s8, 1685968bf842SPeter Maydell gen_helper_neon_widen_s16, 1686968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1687968bf842SPeter Maydell }; 1688968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1689968bf842SPeter Maydell } 1690968bf842SPeter Maydell 1691968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1692968bf842SPeter Maydell { 1693448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1694968bf842SPeter Maydell gen_helper_neon_widen_u8, 1695968bf842SPeter Maydell gen_helper_neon_widen_u16, 1696968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1697968bf842SPeter Maydell }; 1698968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1699968bf842SPeter Maydell } 17003da26f11SPeter Maydell 17013da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 17027b959c58SPeter Maydell gen_helper_gvec_2_ptr *fn) 17033da26f11SPeter Maydell { 17043da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 17057b959c58SPeter Maydell int vec_size = a->q ? 16 : 8; 1706015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1707015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 17087b959c58SPeter Maydell TCGv_ptr fpst; 17093da26f11SPeter Maydell 17103da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17113da26f11SPeter Maydell return false; 17123da26f11SPeter Maydell } 17133da26f11SPeter Maydell 17140ae715c6SPeter Maydell if (a->size == MO_16) { 17157b959c58SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 17167b959c58SPeter Maydell return false; 17177b959c58SPeter Maydell } 17187b959c58SPeter Maydell } 17197b959c58SPeter Maydell 17203da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17213da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 17223da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 17233da26f11SPeter Maydell return false; 17243da26f11SPeter Maydell } 17253da26f11SPeter Maydell 17263da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 17273da26f11SPeter Maydell return false; 17283da26f11SPeter Maydell } 17293da26f11SPeter Maydell 17303da26f11SPeter Maydell if (!vfp_access_check(s)) { 17313da26f11SPeter Maydell return true; 17323da26f11SPeter Maydell } 17333da26f11SPeter Maydell 17340ae715c6SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 17357b959c58SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn); 17367b959c58SPeter Maydell tcg_temp_free_ptr(fpst); 17373da26f11SPeter Maydell return true; 17383da26f11SPeter Maydell } 17393da26f11SPeter Maydell 17403da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 17413da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 17423da26f11SPeter Maydell { \ 17433da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 17443da26f11SPeter Maydell } 17453da26f11SPeter Maydell 17467b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 17477b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 17487b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 17497b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) 17502c35a39eSPeter Maydell 175124018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) 175224018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) 175324018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 175424018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) 175524018cf3SPeter Maydell 17562c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 17572c35a39eSPeter Maydell GVecGen2iFn *fn) 17582c35a39eSPeter Maydell { 17592c35a39eSPeter Maydell uint64_t imm; 17602c35a39eSPeter Maydell int reg_ofs, vec_size; 17612c35a39eSPeter Maydell 17622c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17632c35a39eSPeter Maydell return false; 17642c35a39eSPeter Maydell } 17652c35a39eSPeter Maydell 17662c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17672c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 17682c35a39eSPeter Maydell return false; 17692c35a39eSPeter Maydell } 17702c35a39eSPeter Maydell 17712c35a39eSPeter Maydell if (a->vd & a->q) { 17722c35a39eSPeter Maydell return false; 17732c35a39eSPeter Maydell } 17742c35a39eSPeter Maydell 17752c35a39eSPeter Maydell if (!vfp_access_check(s)) { 17762c35a39eSPeter Maydell return true; 17772c35a39eSPeter Maydell } 17782c35a39eSPeter Maydell 1779015ee81aSRichard Henderson reg_ofs = neon_full_reg_offset(a->vd); 17802c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 17812c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 17822c35a39eSPeter Maydell 17832c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 17842c35a39eSPeter Maydell return true; 17852c35a39eSPeter Maydell } 17862c35a39eSPeter Maydell 17872c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 17882c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 17892c35a39eSPeter Maydell { 17902c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 17912c35a39eSPeter Maydell } 17922c35a39eSPeter Maydell 17932c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 17942c35a39eSPeter Maydell { 17952c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 17962c35a39eSPeter Maydell GVecGen2iFn *fn; 17972c35a39eSPeter Maydell 17982c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 17992c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 18002c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 18012c35a39eSPeter Maydell } else { 18022c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 18032c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 18042c35a39eSPeter Maydell return false; 18052c35a39eSPeter Maydell } 18062c35a39eSPeter Maydell fn = gen_VMOV_1r; 18072c35a39eSPeter Maydell } 18082c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 18092c35a39eSPeter Maydell } 1810b28be095SPeter Maydell 1811b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1812b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1813b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 18148aab18a2SRichard Henderson int src1_mop, int src2_mop) 1815b28be095SPeter Maydell { 1816b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1817b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1818b28be095SPeter Maydell 1819b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1820b28be095SPeter Maydell return false; 1821b28be095SPeter Maydell } 1822b28be095SPeter Maydell 1823b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1824b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1825b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1826b28be095SPeter Maydell return false; 1827b28be095SPeter Maydell } 1828b28be095SPeter Maydell 18298aab18a2SRichard Henderson if (!opfn) { 1830b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1831b28be095SPeter Maydell return false; 1832b28be095SPeter Maydell } 1833b28be095SPeter Maydell 1834fc313c64SFrédéric Pétrot if ((a->vd & 1) || (src1_mop == MO_UQ && (a->vn & 1))) { 1835b28be095SPeter Maydell return false; 1836b28be095SPeter Maydell } 1837b28be095SPeter Maydell 1838b28be095SPeter Maydell if (!vfp_access_check(s)) { 1839b28be095SPeter Maydell return true; 1840b28be095SPeter Maydell } 1841b28be095SPeter Maydell 1842b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1843b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1844b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1845b28be095SPeter Maydell 18468aab18a2SRichard Henderson if (src1_mop >= 0) { 18478aab18a2SRichard Henderson read_neon_element64(rn0_64, a->vn, 0, src1_mop); 1848b28be095SPeter Maydell } else { 1849a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1850a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1851b28be095SPeter Maydell widenfn(rn0_64, tmp); 1852b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1853b28be095SPeter Maydell } 18548aab18a2SRichard Henderson if (src2_mop >= 0) { 18558aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 0, src2_mop); 18568aab18a2SRichard Henderson } else { 18578aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18588aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 18598aab18a2SRichard Henderson widenfn(rm_64, tmp); 18608aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 18618aab18a2SRichard Henderson } 1862b28be095SPeter Maydell 1863b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1864b28be095SPeter Maydell 1865b28be095SPeter Maydell /* 1866b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1867b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1868b28be095SPeter Maydell */ 18698aab18a2SRichard Henderson if (src1_mop >= 0) { 18708aab18a2SRichard Henderson read_neon_element64(rn1_64, a->vn, 1, src1_mop); 1871b28be095SPeter Maydell } else { 1872a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1873a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 1, MO_32); 1874b28be095SPeter Maydell widenfn(rn1_64, tmp); 1875b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1876b28be095SPeter Maydell } 18778aab18a2SRichard Henderson if (src2_mop >= 0) { 18788aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 1, src2_mop); 18798aab18a2SRichard Henderson } else { 18808aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18818aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 1, MO_32); 18828aab18a2SRichard Henderson widenfn(rm_64, tmp); 18838aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 18848aab18a2SRichard Henderson } 1885b28be095SPeter Maydell 18860aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 1887b28be095SPeter Maydell 1888b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 18890aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 1890b28be095SPeter Maydell 1891b28be095SPeter Maydell tcg_temp_free_i64(rn0_64); 1892b28be095SPeter Maydell tcg_temp_free_i64(rn1_64); 1893b28be095SPeter Maydell tcg_temp_free_i64(rm_64); 1894b28be095SPeter Maydell 1895b28be095SPeter Maydell return true; 1896b28be095SPeter Maydell } 1897b28be095SPeter Maydell 18988aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN) \ 1899b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1900b28be095SPeter Maydell { \ 1901b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1902b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1903b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 19048aab18a2SRichard Henderson NULL, NULL, \ 1905b28be095SPeter Maydell }; \ 1906b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1907b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1908b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1909b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1910b28be095SPeter Maydell NULL, \ 1911b28be095SPeter Maydell }; \ 19128aab18a2SRichard Henderson int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \ 19138aab18a2SRichard Henderson return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \ 1914fc313c64SFrédéric Pétrot SRC1WIDE ? MO_UQ : narrow_mop, \ 19158aab18a2SRichard Henderson narrow_mop); \ 1916b28be095SPeter Maydell } 1917b28be095SPeter Maydell 19188aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN) 19198aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0) 19208aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN) 19218aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0) 19228aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN) 19238aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0) 19248aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN) 19258aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0) 19260fa1ab03SPeter Maydell 19270fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 19280fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 19290fa1ab03SPeter Maydell { 19300fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 19310fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 19320fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 19330fa1ab03SPeter Maydell 19340fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 19350fa1ab03SPeter Maydell return false; 19360fa1ab03SPeter Maydell } 19370fa1ab03SPeter Maydell 19380fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 19390fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 19400fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 19410fa1ab03SPeter Maydell return false; 19420fa1ab03SPeter Maydell } 19430fa1ab03SPeter Maydell 19440fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 19450fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 19460fa1ab03SPeter Maydell return false; 19470fa1ab03SPeter Maydell } 19480fa1ab03SPeter Maydell 19490fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 19500fa1ab03SPeter Maydell return false; 19510fa1ab03SPeter Maydell } 19520fa1ab03SPeter Maydell 19530fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 19540fa1ab03SPeter Maydell return true; 19550fa1ab03SPeter Maydell } 19560fa1ab03SPeter Maydell 19570fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 19580fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 19590fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 19600fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 19610fa1ab03SPeter Maydell 19620aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 0, MO_64); 19630aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 0, MO_64); 19640fa1ab03SPeter Maydell 19650fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19660fa1ab03SPeter Maydell 19670fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 19680fa1ab03SPeter Maydell 19690aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 1, MO_64); 19700aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 1, MO_64); 19710fa1ab03SPeter Maydell 19720fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19730fa1ab03SPeter Maydell 19740fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 19750fa1ab03SPeter Maydell 1976a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 1977a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 19780fa1ab03SPeter Maydell 1979a712266fSRichard Henderson tcg_temp_free_i32(rd0); 1980a712266fSRichard Henderson tcg_temp_free_i32(rd1); 19810fa1ab03SPeter Maydell tcg_temp_free_i64(rn_64); 19820fa1ab03SPeter Maydell tcg_temp_free_i64(rm_64); 19830fa1ab03SPeter Maydell 19840fa1ab03SPeter Maydell return true; 19850fa1ab03SPeter Maydell } 19860fa1ab03SPeter Maydell 19870fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 19880fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 19890fa1ab03SPeter Maydell { \ 19900fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 19910fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 19920fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 19930fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 19940fa1ab03SPeter Maydell NULL, \ 19950fa1ab03SPeter Maydell }; \ 19960fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 19970fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 19980fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 19990fa1ab03SPeter Maydell EXTOP, \ 20000fa1ab03SPeter Maydell NULL, \ 20010fa1ab03SPeter Maydell }; \ 20020fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 20030fa1ab03SPeter Maydell } 20040fa1ab03SPeter Maydell 20050fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 20060fa1ab03SPeter Maydell { 20070fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 20080fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 20090fa1ab03SPeter Maydell } 20100fa1ab03SPeter Maydell 20110fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 20120fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 20130fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 20140fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 2015f5b28401SPeter Maydell 2016f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 2017f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 2018f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 2019f5b28401SPeter Maydell { 2020f5b28401SPeter Maydell /* 2021f5b28401SPeter Maydell * 3-regs different lengths, long operations. 2022f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 2023f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 2024f5b28401SPeter Maydell * that result into the double-width destination. 2025f5b28401SPeter Maydell */ 2026f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 2027f5b28401SPeter Maydell TCGv_i32 rn, rm; 2028f5b28401SPeter Maydell 2029f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2030f5b28401SPeter Maydell return false; 2031f5b28401SPeter Maydell } 2032f5b28401SPeter Maydell 2033f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2034f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2035f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2036f5b28401SPeter Maydell return false; 2037f5b28401SPeter Maydell } 2038f5b28401SPeter Maydell 2039f5b28401SPeter Maydell if (!opfn) { 2040f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 2041f5b28401SPeter Maydell return false; 2042f5b28401SPeter Maydell } 2043f5b28401SPeter Maydell 2044f5b28401SPeter Maydell if (a->vd & 1) { 2045f5b28401SPeter Maydell return false; 2046f5b28401SPeter Maydell } 2047f5b28401SPeter Maydell 2048f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2049f5b28401SPeter Maydell return true; 2050f5b28401SPeter Maydell } 2051f5b28401SPeter Maydell 2052f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2053f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2054f5b28401SPeter Maydell 2055a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2056a712266fSRichard Henderson rm = tcg_temp_new_i32(); 2057a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 2058a712266fSRichard Henderson read_neon_element32(rm, a->vm, 0, MO_32); 2059f5b28401SPeter Maydell opfn(rd0, rn, rm); 2060f5b28401SPeter Maydell 2061a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 2062a712266fSRichard Henderson read_neon_element32(rm, a->vm, 1, MO_32); 2063f5b28401SPeter Maydell opfn(rd1, rn, rm); 2064f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2065f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2066f5b28401SPeter Maydell 2067f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2068f5b28401SPeter Maydell if (accfn) { 2069f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 20700aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 0, MO_64); 20719f1a5f93SRichard Henderson accfn(rd0, tmp, rd0); 20720aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 1, MO_64); 20739f1a5f93SRichard Henderson accfn(rd1, tmp, rd1); 2074f5b28401SPeter Maydell tcg_temp_free_i64(tmp); 2075f5b28401SPeter Maydell } 2076f5b28401SPeter Maydell 20779f1a5f93SRichard Henderson write_neon_element64(rd0, a->vd, 0, MO_64); 20789f1a5f93SRichard Henderson write_neon_element64(rd1, a->vd, 1, MO_64); 2079f5b28401SPeter Maydell tcg_temp_free_i64(rd0); 2080f5b28401SPeter Maydell tcg_temp_free_i64(rd1); 2081f5b28401SPeter Maydell 2082f5b28401SPeter Maydell return true; 2083f5b28401SPeter Maydell } 2084f5b28401SPeter Maydell 2085f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2086f5b28401SPeter Maydell { 2087f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2088f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2089f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2090f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2091f5b28401SPeter Maydell NULL, 2092f5b28401SPeter Maydell }; 2093f5b28401SPeter Maydell 2094f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2095f5b28401SPeter Maydell } 2096f5b28401SPeter Maydell 2097f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2098f5b28401SPeter Maydell { 2099f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2100f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2101f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2102f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2103f5b28401SPeter Maydell NULL, 2104f5b28401SPeter Maydell }; 2105f5b28401SPeter Maydell 2106f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2107f5b28401SPeter Maydell } 2108f5b28401SPeter Maydell 2109f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2110f5b28401SPeter Maydell { 2111f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2112f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2113f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2114f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2115f5b28401SPeter Maydell NULL, 2116f5b28401SPeter Maydell }; 2117f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2118f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2119f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2120f5b28401SPeter Maydell tcg_gen_add_i64, 2121f5b28401SPeter Maydell NULL, 2122f5b28401SPeter Maydell }; 2123f5b28401SPeter Maydell 2124f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2125f5b28401SPeter Maydell } 2126f5b28401SPeter Maydell 2127f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2128f5b28401SPeter Maydell { 2129f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2130f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2131f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2132f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2133f5b28401SPeter Maydell NULL, 2134f5b28401SPeter Maydell }; 2135f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2136f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2137f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2138f5b28401SPeter Maydell tcg_gen_add_i64, 2139f5b28401SPeter Maydell NULL, 2140f5b28401SPeter Maydell }; 2141f5b28401SPeter Maydell 2142f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2143f5b28401SPeter Maydell } 21443a1d9eb0SPeter Maydell 21453a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21463a1d9eb0SPeter Maydell { 21473a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21483a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21493a1d9eb0SPeter Maydell 21503a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 21513a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21523a1d9eb0SPeter Maydell 21533a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21543a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21553a1d9eb0SPeter Maydell } 21563a1d9eb0SPeter Maydell 21573a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21583a1d9eb0SPeter Maydell { 21593a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21603a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21613a1d9eb0SPeter Maydell 21623a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 21633a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21643a1d9eb0SPeter Maydell 21653a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21663a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21673a1d9eb0SPeter Maydell } 21683a1d9eb0SPeter Maydell 21693a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 21703a1d9eb0SPeter Maydell { 21713a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21723a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 21733a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 21743a1d9eb0SPeter Maydell gen_mull_s32, 21753a1d9eb0SPeter Maydell NULL, 21763a1d9eb0SPeter Maydell }; 21773a1d9eb0SPeter Maydell 21783a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21793a1d9eb0SPeter Maydell } 21803a1d9eb0SPeter Maydell 21813a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 21823a1d9eb0SPeter Maydell { 21833a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21843a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 21853a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 21863a1d9eb0SPeter Maydell gen_mull_u32, 21873a1d9eb0SPeter Maydell NULL, 21883a1d9eb0SPeter Maydell }; 21893a1d9eb0SPeter Maydell 21903a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21913a1d9eb0SPeter Maydell } 21923a1d9eb0SPeter Maydell 21933a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 21943a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 21953a1d9eb0SPeter Maydell { \ 21963a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 21973a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 21983a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 21993a1d9eb0SPeter Maydell gen_##MULL##32, \ 22003a1d9eb0SPeter Maydell NULL, \ 22013a1d9eb0SPeter Maydell }; \ 22023a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 22033a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 22043a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 22053a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 22063a1d9eb0SPeter Maydell NULL, \ 22073a1d9eb0SPeter Maydell }; \ 22083a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 22093a1d9eb0SPeter Maydell } 22103a1d9eb0SPeter Maydell 22113a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 22123a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 22133a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 22143a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 22159546ca59SPeter Maydell 22169546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22179546ca59SPeter Maydell { 22189546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 22199546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 22209546ca59SPeter Maydell } 22219546ca59SPeter Maydell 22229546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22239546ca59SPeter Maydell { 22249546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 22259546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 22269546ca59SPeter Maydell } 22279546ca59SPeter Maydell 22289546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 22299546ca59SPeter Maydell { 22309546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22319546ca59SPeter Maydell NULL, 22329546ca59SPeter Maydell gen_VQDMULL_16, 22339546ca59SPeter Maydell gen_VQDMULL_32, 22349546ca59SPeter Maydell NULL, 22359546ca59SPeter Maydell }; 22369546ca59SPeter Maydell 22379546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22389546ca59SPeter Maydell } 22399546ca59SPeter Maydell 22409546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22419546ca59SPeter Maydell { 22429546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22439546ca59SPeter Maydell } 22449546ca59SPeter Maydell 22459546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22469546ca59SPeter Maydell { 22479546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22489546ca59SPeter Maydell } 22499546ca59SPeter Maydell 22509546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 22519546ca59SPeter Maydell { 22529546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22539546ca59SPeter Maydell NULL, 22549546ca59SPeter Maydell gen_VQDMULL_16, 22559546ca59SPeter Maydell gen_VQDMULL_32, 22569546ca59SPeter Maydell NULL, 22579546ca59SPeter Maydell }; 22589546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22599546ca59SPeter Maydell NULL, 22609546ca59SPeter Maydell gen_VQDMLAL_acc_16, 22619546ca59SPeter Maydell gen_VQDMLAL_acc_32, 22629546ca59SPeter Maydell NULL, 22639546ca59SPeter Maydell }; 22649546ca59SPeter Maydell 22659546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22669546ca59SPeter Maydell } 22679546ca59SPeter Maydell 22689546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22699546ca59SPeter Maydell { 22709546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 22719546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22729546ca59SPeter Maydell } 22739546ca59SPeter Maydell 22749546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22759546ca59SPeter Maydell { 22769546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 22779546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22789546ca59SPeter Maydell } 22799546ca59SPeter Maydell 22809546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 22819546ca59SPeter Maydell { 22829546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22839546ca59SPeter Maydell NULL, 22849546ca59SPeter Maydell gen_VQDMULL_16, 22859546ca59SPeter Maydell gen_VQDMULL_32, 22869546ca59SPeter Maydell NULL, 22879546ca59SPeter Maydell }; 22889546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22899546ca59SPeter Maydell NULL, 22909546ca59SPeter Maydell gen_VQDMLSL_acc_16, 22919546ca59SPeter Maydell gen_VQDMLSL_acc_32, 22929546ca59SPeter Maydell NULL, 22939546ca59SPeter Maydell }; 22949546ca59SPeter Maydell 22959546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22969546ca59SPeter Maydell } 229718fb58d5SPeter Maydell 229818fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 229918fb58d5SPeter Maydell { 230018fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 230118fb58d5SPeter Maydell 230218fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 230318fb58d5SPeter Maydell return false; 230418fb58d5SPeter Maydell } 230518fb58d5SPeter Maydell 230618fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 230718fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 230818fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 230918fb58d5SPeter Maydell return false; 231018fb58d5SPeter Maydell } 231118fb58d5SPeter Maydell 231218fb58d5SPeter Maydell if (a->vd & 1) { 231318fb58d5SPeter Maydell return false; 231418fb58d5SPeter Maydell } 231518fb58d5SPeter Maydell 231618fb58d5SPeter Maydell switch (a->size) { 231718fb58d5SPeter Maydell case 0: 231818fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 231918fb58d5SPeter Maydell break; 232018fb58d5SPeter Maydell case 2: 232118fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 232218fb58d5SPeter Maydell return false; 232318fb58d5SPeter Maydell } 232418fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 232518fb58d5SPeter Maydell break; 232618fb58d5SPeter Maydell default: 232718fb58d5SPeter Maydell return false; 232818fb58d5SPeter Maydell } 232918fb58d5SPeter Maydell 233018fb58d5SPeter Maydell if (!vfp_access_check(s)) { 233118fb58d5SPeter Maydell return true; 233218fb58d5SPeter Maydell } 233318fb58d5SPeter Maydell 2334015ee81aSRichard Henderson tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd), 2335015ee81aSRichard Henderson neon_full_reg_offset(a->vn), 2336015ee81aSRichard Henderson neon_full_reg_offset(a->vm), 233718fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 233818fb58d5SPeter Maydell return true; 233918fb58d5SPeter Maydell } 234096fc80f5SPeter Maydell 234196fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 234296fc80f5SPeter Maydell { 234396fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 234496fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 234596fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 234696fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 234796fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 234896fc80f5SPeter Maydell } 234996fc80f5SPeter Maydell 235096fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 235196fc80f5SPeter Maydell { 235296fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 235396fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 235496fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 235596fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 235696fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 235796fc80f5SPeter Maydell } 235896fc80f5SPeter Maydell 235996fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 236096fc80f5SPeter Maydell { 2361a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 2362a712266fSRichard Henderson if (size == MO_16) { 2363a712266fSRichard Henderson read_neon_element32(tmp, reg & 7, reg >> 4, MO_32); 236496fc80f5SPeter Maydell if (reg & 8) { 236596fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 236696fc80f5SPeter Maydell } else { 236796fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 236896fc80f5SPeter Maydell } 236996fc80f5SPeter Maydell } else { 2370a712266fSRichard Henderson read_neon_element32(tmp, reg & 15, reg >> 4, MO_32); 237196fc80f5SPeter Maydell } 237296fc80f5SPeter Maydell return tmp; 237396fc80f5SPeter Maydell } 237496fc80f5SPeter Maydell 237596fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 237696fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 237796fc80f5SPeter Maydell { 237896fc80f5SPeter Maydell /* 237996fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 238096fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 238196fc80f5SPeter Maydell * perform an accumulation operation of that result into the 238296fc80f5SPeter Maydell * destination. 238396fc80f5SPeter Maydell */ 2384a712266fSRichard Henderson TCGv_i32 scalar, tmp; 238596fc80f5SPeter Maydell int pass; 238696fc80f5SPeter Maydell 238796fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 238896fc80f5SPeter Maydell return false; 238996fc80f5SPeter Maydell } 239096fc80f5SPeter Maydell 239196fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 239296fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 239396fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 239496fc80f5SPeter Maydell return false; 239596fc80f5SPeter Maydell } 239696fc80f5SPeter Maydell 239796fc80f5SPeter Maydell if (!opfn) { 239896fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 239996fc80f5SPeter Maydell return false; 240096fc80f5SPeter Maydell } 240196fc80f5SPeter Maydell 240296fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 240396fc80f5SPeter Maydell return false; 240496fc80f5SPeter Maydell } 240596fc80f5SPeter Maydell 240696fc80f5SPeter Maydell if (!vfp_access_check(s)) { 240796fc80f5SPeter Maydell return true; 240896fc80f5SPeter Maydell } 240996fc80f5SPeter Maydell 241096fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2411a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 241296fc80f5SPeter Maydell 241396fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2414a712266fSRichard Henderson read_neon_element32(tmp, a->vn, pass, MO_32); 241596fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 241696fc80f5SPeter Maydell if (accfn) { 2417a712266fSRichard Henderson TCGv_i32 rd = tcg_temp_new_i32(); 2418a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 241996fc80f5SPeter Maydell accfn(tmp, rd, tmp); 242096fc80f5SPeter Maydell tcg_temp_free_i32(rd); 242196fc80f5SPeter Maydell } 2422a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 242396fc80f5SPeter Maydell } 2424a712266fSRichard Henderson tcg_temp_free_i32(tmp); 242596fc80f5SPeter Maydell tcg_temp_free_i32(scalar); 242696fc80f5SPeter Maydell return true; 242796fc80f5SPeter Maydell } 242896fc80f5SPeter Maydell 242996fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 243096fc80f5SPeter Maydell { 243196fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 243296fc80f5SPeter Maydell NULL, 243396fc80f5SPeter Maydell gen_helper_neon_mul_u16, 243496fc80f5SPeter Maydell tcg_gen_mul_i32, 243596fc80f5SPeter Maydell NULL, 243696fc80f5SPeter Maydell }; 243796fc80f5SPeter Maydell 243896fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 243996fc80f5SPeter Maydell } 244096fc80f5SPeter Maydell 244196fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 244296fc80f5SPeter Maydell { 244396fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 244496fc80f5SPeter Maydell NULL, 244596fc80f5SPeter Maydell gen_helper_neon_mul_u16, 244696fc80f5SPeter Maydell tcg_gen_mul_i32, 244796fc80f5SPeter Maydell NULL, 244896fc80f5SPeter Maydell }; 244996fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 245096fc80f5SPeter Maydell NULL, 245196fc80f5SPeter Maydell gen_helper_neon_add_u16, 245296fc80f5SPeter Maydell tcg_gen_add_i32, 245396fc80f5SPeter Maydell NULL, 245496fc80f5SPeter Maydell }; 245596fc80f5SPeter Maydell 245696fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 245796fc80f5SPeter Maydell } 245896fc80f5SPeter Maydell 245996fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 246096fc80f5SPeter Maydell { 246196fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 246296fc80f5SPeter Maydell NULL, 246396fc80f5SPeter Maydell gen_helper_neon_mul_u16, 246496fc80f5SPeter Maydell tcg_gen_mul_i32, 246596fc80f5SPeter Maydell NULL, 246696fc80f5SPeter Maydell }; 246796fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 246896fc80f5SPeter Maydell NULL, 246996fc80f5SPeter Maydell gen_helper_neon_sub_u16, 247096fc80f5SPeter Maydell tcg_gen_sub_i32, 247196fc80f5SPeter Maydell NULL, 247296fc80f5SPeter Maydell }; 247396fc80f5SPeter Maydell 247496fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 247596fc80f5SPeter Maydell } 247685ac9aefSPeter Maydell 2477fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, 2478fc8ae790SPeter Maydell gen_helper_gvec_3_ptr *fn) 2479fc8ae790SPeter Maydell { 2480fc8ae790SPeter Maydell /* Two registers and a scalar, using gvec */ 2481fc8ae790SPeter Maydell int vec_size = a->q ? 16 : 8; 2482015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 2483015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 2484fc8ae790SPeter Maydell int rm_ofs; 2485fc8ae790SPeter Maydell int idx; 2486fc8ae790SPeter Maydell TCGv_ptr fpstatus; 2487fc8ae790SPeter Maydell 2488fc8ae790SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2489fc8ae790SPeter Maydell return false; 2490fc8ae790SPeter Maydell } 2491fc8ae790SPeter Maydell 2492fc8ae790SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2493fc8ae790SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2494fc8ae790SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2495fc8ae790SPeter Maydell return false; 2496fc8ae790SPeter Maydell } 2497fc8ae790SPeter Maydell 2498fc8ae790SPeter Maydell if (!fn) { 2499fc8ae790SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2500fc8ae790SPeter Maydell return false; 2501fc8ae790SPeter Maydell } 2502fc8ae790SPeter Maydell 2503fc8ae790SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2504fc8ae790SPeter Maydell return false; 2505fc8ae790SPeter Maydell } 2506fc8ae790SPeter Maydell 2507fc8ae790SPeter Maydell if (!vfp_access_check(s)) { 2508fc8ae790SPeter Maydell return true; 2509fc8ae790SPeter Maydell } 2510fc8ae790SPeter Maydell 2511fc8ae790SPeter Maydell /* a->vm is M:Vm, which encodes both register and index */ 2512fc8ae790SPeter Maydell idx = extract32(a->vm, a->size + 2, 2); 2513fc8ae790SPeter Maydell a->vm = extract32(a->vm, 0, a->size + 2); 2514015ee81aSRichard Henderson rm_ofs = neon_full_reg_offset(a->vm); 2515fc8ae790SPeter Maydell 2516fc8ae790SPeter Maydell fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD); 2517fc8ae790SPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus, 2518fc8ae790SPeter Maydell vec_size, vec_size, idx, fn); 2519fc8ae790SPeter Maydell tcg_temp_free_ptr(fpstatus); 2520fc8ae790SPeter Maydell return true; 2521fc8ae790SPeter Maydell } 2522fc8ae790SPeter Maydell 2523fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC) \ 2524fc8ae790SPeter Maydell static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \ 252585ac9aefSPeter Maydell { \ 2526fc8ae790SPeter Maydell static gen_helper_gvec_3_ptr * const opfn[] = { \ 2527fc8ae790SPeter Maydell NULL, \ 2528fc8ae790SPeter Maydell gen_helper_##FUNC##_h, \ 2529fc8ae790SPeter Maydell gen_helper_##FUNC##_s, \ 2530fc8ae790SPeter Maydell NULL, \ 2531fc8ae790SPeter Maydell }; \ 2532fc8ae790SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \ 2533fc8ae790SPeter Maydell return false; \ 2534fc8ae790SPeter Maydell } \ 2535fc8ae790SPeter Maydell return do_2scalar_fp_vec(s, a, opfn[a->size]); \ 253685ac9aefSPeter Maydell } 253785ac9aefSPeter Maydell 2538fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx) 2539fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx) 2540fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx) 2541b2fc7be9SPeter Maydell 2542b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2543b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2544b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2545b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2546b2fc7be9SPeter Maydell 2547b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2548b2fc7be9SPeter Maydell { 2549b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2550b2fc7be9SPeter Maydell NULL, 2551b2fc7be9SPeter Maydell gen_VQDMULH_16, 2552b2fc7be9SPeter Maydell gen_VQDMULH_32, 2553b2fc7be9SPeter Maydell NULL, 2554b2fc7be9SPeter Maydell }; 2555b2fc7be9SPeter Maydell 2556b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2557b2fc7be9SPeter Maydell } 2558b2fc7be9SPeter Maydell 2559b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2560b2fc7be9SPeter Maydell { 2561b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2562b2fc7be9SPeter Maydell NULL, 2563b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2564b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2565b2fc7be9SPeter Maydell NULL, 2566b2fc7be9SPeter Maydell }; 2567b2fc7be9SPeter Maydell 2568b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2569b2fc7be9SPeter Maydell } 2570aa318f5bSPeter Maydell 2571aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2572aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2573aa318f5bSPeter Maydell { 2574aa318f5bSPeter Maydell /* 2575aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2576aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2577aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2578aa318f5bSPeter Maydell */ 2579a712266fSRichard Henderson TCGv_i32 scalar, rn, rd; 2580aa318f5bSPeter Maydell int pass; 2581aa318f5bSPeter Maydell 2582aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2583aa318f5bSPeter Maydell return false; 2584aa318f5bSPeter Maydell } 2585aa318f5bSPeter Maydell 2586aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2587aa318f5bSPeter Maydell return false; 2588aa318f5bSPeter Maydell } 2589aa318f5bSPeter Maydell 2590aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2591aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2592aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2593aa318f5bSPeter Maydell return false; 2594aa318f5bSPeter Maydell } 2595aa318f5bSPeter Maydell 2596aa318f5bSPeter Maydell if (!opfn) { 2597aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2598aa318f5bSPeter Maydell return false; 2599aa318f5bSPeter Maydell } 2600aa318f5bSPeter Maydell 2601aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2602aa318f5bSPeter Maydell return false; 2603aa318f5bSPeter Maydell } 2604aa318f5bSPeter Maydell 2605aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2606aa318f5bSPeter Maydell return true; 2607aa318f5bSPeter Maydell } 2608aa318f5bSPeter Maydell 2609aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2610a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2611a712266fSRichard Henderson rd = tcg_temp_new_i32(); 2612aa318f5bSPeter Maydell 2613aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2614a712266fSRichard Henderson read_neon_element32(rn, a->vn, pass, MO_32); 2615a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 2616aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2617a712266fSRichard Henderson write_neon_element32(rd, a->vd, pass, MO_32); 2618aa318f5bSPeter Maydell } 2619a712266fSRichard Henderson tcg_temp_free_i32(rn); 2620a712266fSRichard Henderson tcg_temp_free_i32(rd); 2621aa318f5bSPeter Maydell tcg_temp_free_i32(scalar); 2622aa318f5bSPeter Maydell 2623aa318f5bSPeter Maydell return true; 2624aa318f5bSPeter Maydell } 2625aa318f5bSPeter Maydell 2626aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2627aa318f5bSPeter Maydell { 2628aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2629aa318f5bSPeter Maydell NULL, 2630aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2631aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2632aa318f5bSPeter Maydell NULL, 2633aa318f5bSPeter Maydell }; 2634aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2635aa318f5bSPeter Maydell } 2636aa318f5bSPeter Maydell 2637aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2638aa318f5bSPeter Maydell { 2639aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2640aa318f5bSPeter Maydell NULL, 2641aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2642aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2643aa318f5bSPeter Maydell NULL, 2644aa318f5bSPeter Maydell }; 2645aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2646aa318f5bSPeter Maydell } 264777e576a9SPeter Maydell 264877e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 264977e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 265077e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 265177e576a9SPeter Maydell { 265277e576a9SPeter Maydell /* 265377e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 265477e576a9SPeter Maydell * operation on the input elements and the scalar which produces 265577e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 265677e576a9SPeter Maydell * operation of that result into the destination. 265777e576a9SPeter Maydell */ 265877e576a9SPeter Maydell TCGv_i32 scalar, rn; 265977e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 266077e576a9SPeter Maydell 266177e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 266277e576a9SPeter Maydell return false; 266377e576a9SPeter Maydell } 266477e576a9SPeter Maydell 266577e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 266677e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 266777e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 266877e576a9SPeter Maydell return false; 266977e576a9SPeter Maydell } 267077e576a9SPeter Maydell 267177e576a9SPeter Maydell if (!opfn) { 267277e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 267377e576a9SPeter Maydell return false; 267477e576a9SPeter Maydell } 267577e576a9SPeter Maydell 267677e576a9SPeter Maydell if (a->vd & 1) { 267777e576a9SPeter Maydell return false; 267877e576a9SPeter Maydell } 267977e576a9SPeter Maydell 268077e576a9SPeter Maydell if (!vfp_access_check(s)) { 268177e576a9SPeter Maydell return true; 268277e576a9SPeter Maydell } 268377e576a9SPeter Maydell 268477e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 268577e576a9SPeter Maydell 268677e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 2687a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2688a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 268977e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 269077e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 269177e576a9SPeter Maydell 2692a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 269377e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 269477e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 269577e576a9SPeter Maydell tcg_temp_free_i32(rn); 269677e576a9SPeter Maydell tcg_temp_free_i32(scalar); 269777e576a9SPeter Maydell 269877e576a9SPeter Maydell if (accfn) { 269977e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 27000aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 0, MO_64); 27019f1a5f93SRichard Henderson accfn(rn0_64, t64, rn0_64); 27020aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 1, MO_64); 27039f1a5f93SRichard Henderson accfn(rn1_64, t64, rn1_64); 270477e576a9SPeter Maydell tcg_temp_free_i64(t64); 27059f1a5f93SRichard Henderson } 27069f1a5f93SRichard Henderson 27070aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 27080aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 270977e576a9SPeter Maydell tcg_temp_free_i64(rn0_64); 271077e576a9SPeter Maydell tcg_temp_free_i64(rn1_64); 271177e576a9SPeter Maydell return true; 271277e576a9SPeter Maydell } 271377e576a9SPeter Maydell 271477e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 271577e576a9SPeter Maydell { 271677e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 271777e576a9SPeter Maydell NULL, 271877e576a9SPeter Maydell gen_helper_neon_mull_s16, 271977e576a9SPeter Maydell gen_mull_s32, 272077e576a9SPeter Maydell NULL, 272177e576a9SPeter Maydell }; 272277e576a9SPeter Maydell 272377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 272477e576a9SPeter Maydell } 272577e576a9SPeter Maydell 272677e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 272777e576a9SPeter Maydell { 272877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 272977e576a9SPeter Maydell NULL, 273077e576a9SPeter Maydell gen_helper_neon_mull_u16, 273177e576a9SPeter Maydell gen_mull_u32, 273277e576a9SPeter Maydell NULL, 273377e576a9SPeter Maydell }; 273477e576a9SPeter Maydell 273577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 273677e576a9SPeter Maydell } 273777e576a9SPeter Maydell 273877e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 273977e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 274077e576a9SPeter Maydell { \ 274177e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 274277e576a9SPeter Maydell NULL, \ 274377e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 274477e576a9SPeter Maydell gen_##MULL##32, \ 274577e576a9SPeter Maydell NULL, \ 274677e576a9SPeter Maydell }; \ 274777e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 274877e576a9SPeter Maydell NULL, \ 274977e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 275077e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 275177e576a9SPeter Maydell NULL, \ 275277e576a9SPeter Maydell }; \ 275377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 275477e576a9SPeter Maydell } 275577e576a9SPeter Maydell 275677e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 275777e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 275877e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 275977e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 276077e576a9SPeter Maydell 276177e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 276277e576a9SPeter Maydell { 276377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 276477e576a9SPeter Maydell NULL, 276577e576a9SPeter Maydell gen_VQDMULL_16, 276677e576a9SPeter Maydell gen_VQDMULL_32, 276777e576a9SPeter Maydell NULL, 276877e576a9SPeter Maydell }; 276977e576a9SPeter Maydell 277077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 277177e576a9SPeter Maydell } 277277e576a9SPeter Maydell 277377e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 277477e576a9SPeter Maydell { 277577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 277677e576a9SPeter Maydell NULL, 277777e576a9SPeter Maydell gen_VQDMULL_16, 277877e576a9SPeter Maydell gen_VQDMULL_32, 277977e576a9SPeter Maydell NULL, 278077e576a9SPeter Maydell }; 278177e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 278277e576a9SPeter Maydell NULL, 278377e576a9SPeter Maydell gen_VQDMLAL_acc_16, 278477e576a9SPeter Maydell gen_VQDMLAL_acc_32, 278577e576a9SPeter Maydell NULL, 278677e576a9SPeter Maydell }; 278777e576a9SPeter Maydell 278877e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 278977e576a9SPeter Maydell } 279077e576a9SPeter Maydell 279177e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 279277e576a9SPeter Maydell { 279377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 279477e576a9SPeter Maydell NULL, 279577e576a9SPeter Maydell gen_VQDMULL_16, 279677e576a9SPeter Maydell gen_VQDMULL_32, 279777e576a9SPeter Maydell NULL, 279877e576a9SPeter Maydell }; 279977e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 280077e576a9SPeter Maydell NULL, 280177e576a9SPeter Maydell gen_VQDMLSL_acc_16, 280277e576a9SPeter Maydell gen_VQDMLSL_acc_32, 280377e576a9SPeter Maydell NULL, 280477e576a9SPeter Maydell }; 280577e576a9SPeter Maydell 280677e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 280777e576a9SPeter Maydell } 28080aad761fSPeter Maydell 28090aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 28100aad761fSPeter Maydell { 28110aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 28120aad761fSPeter Maydell return false; 28130aad761fSPeter Maydell } 28140aad761fSPeter Maydell 28150aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28160aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28170aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 28180aad761fSPeter Maydell return false; 28190aad761fSPeter Maydell } 28200aad761fSPeter Maydell 28210aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 28220aad761fSPeter Maydell return false; 28230aad761fSPeter Maydell } 28240aad761fSPeter Maydell 28250aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 28260aad761fSPeter Maydell return false; 28270aad761fSPeter Maydell } 28280aad761fSPeter Maydell 28290aad761fSPeter Maydell if (!vfp_access_check(s)) { 28300aad761fSPeter Maydell return true; 28310aad761fSPeter Maydell } 28320aad761fSPeter Maydell 28330aad761fSPeter Maydell if (!a->q) { 28340aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 28350aad761fSPeter Maydell TCGv_i64 left, right, dest; 28360aad761fSPeter Maydell 28370aad761fSPeter Maydell left = tcg_temp_new_i64(); 28380aad761fSPeter Maydell right = tcg_temp_new_i64(); 28390aad761fSPeter Maydell dest = tcg_temp_new_i64(); 28400aad761fSPeter Maydell 28410aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 28420aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 28430aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 28440aa8e700SRichard Henderson write_neon_element64(dest, a->vd, 0, MO_64); 28450aad761fSPeter Maydell 28460aad761fSPeter Maydell tcg_temp_free_i64(left); 28470aad761fSPeter Maydell tcg_temp_free_i64(right); 28480aad761fSPeter Maydell tcg_temp_free_i64(dest); 28490aad761fSPeter Maydell } else { 28500aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 28510aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 28520aad761fSPeter Maydell 28530aad761fSPeter Maydell left = tcg_temp_new_i64(); 28540aad761fSPeter Maydell middle = tcg_temp_new_i64(); 28550aad761fSPeter Maydell right = tcg_temp_new_i64(); 28560aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 28570aad761fSPeter Maydell destright = tcg_temp_new_i64(); 28580aad761fSPeter Maydell 28590aad761fSPeter Maydell if (a->imm < 8) { 28600aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 28610aa8e700SRichard Henderson read_neon_element64(middle, a->vn, 1, MO_64); 28620aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 28630aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 28640aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 28650aad761fSPeter Maydell } else { 28660aa8e700SRichard Henderson read_neon_element64(right, a->vn, 1, MO_64); 28670aa8e700SRichard Henderson read_neon_element64(middle, a->vm, 0, MO_64); 28680aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 28690aa8e700SRichard Henderson read_neon_element64(left, a->vm, 1, MO_64); 28700aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 28710aad761fSPeter Maydell } 28720aad761fSPeter Maydell 28730aa8e700SRichard Henderson write_neon_element64(destright, a->vd, 0, MO_64); 28740aa8e700SRichard Henderson write_neon_element64(destleft, a->vd, 1, MO_64); 28750aad761fSPeter Maydell 28760aad761fSPeter Maydell tcg_temp_free_i64(destright); 28770aad761fSPeter Maydell tcg_temp_free_i64(destleft); 28780aad761fSPeter Maydell tcg_temp_free_i64(right); 28790aad761fSPeter Maydell tcg_temp_free_i64(middle); 28800aad761fSPeter Maydell tcg_temp_free_i64(left); 28810aad761fSPeter Maydell } 28820aad761fSPeter Maydell return true; 28830aad761fSPeter Maydell } 288454e96c74SPeter Maydell 288554e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 288654e96c74SPeter Maydell { 2887604cef3eSRichard Henderson TCGv_i64 val, def; 2888604cef3eSRichard Henderson TCGv_i32 desc; 288954e96c74SPeter Maydell 289054e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 289154e96c74SPeter Maydell return false; 289254e96c74SPeter Maydell } 289354e96c74SPeter Maydell 289454e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 289554e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 289654e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 289754e96c74SPeter Maydell return false; 289854e96c74SPeter Maydell } 289954e96c74SPeter Maydell 2900604cef3eSRichard Henderson if ((a->vn + a->len + 1) > 32) { 290154e96c74SPeter Maydell /* 290254e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 290354e96c74SPeter Maydell * helper function running off the end of the register file. 290454e96c74SPeter Maydell */ 290554e96c74SPeter Maydell return false; 290654e96c74SPeter Maydell } 2907a712266fSRichard Henderson 2908b6c56c8aSPeter Maydell if (!vfp_access_check(s)) { 2909b6c56c8aSPeter Maydell return true; 2910b6c56c8aSPeter Maydell } 2911b6c56c8aSPeter Maydell 2912d9b47e97SRichard Henderson desc = tcg_constant_i32((a->vn << 2) | a->len); 2913604cef3eSRichard Henderson def = tcg_temp_new_i64(); 291454e96c74SPeter Maydell if (a->op) { 2915604cef3eSRichard Henderson read_neon_element64(def, a->vd, 0, MO_64); 291654e96c74SPeter Maydell } else { 2917604cef3eSRichard Henderson tcg_gen_movi_i64(def, 0); 291854e96c74SPeter Maydell } 2919604cef3eSRichard Henderson val = tcg_temp_new_i64(); 2920604cef3eSRichard Henderson read_neon_element64(val, a->vm, 0, MO_64); 2921a712266fSRichard Henderson 2922604cef3eSRichard Henderson gen_helper_neon_tbl(val, cpu_env, desc, val, def); 2923604cef3eSRichard Henderson write_neon_element64(val, a->vd, 0, MO_64); 2924604cef3eSRichard Henderson 2925604cef3eSRichard Henderson tcg_temp_free_i64(def); 2926604cef3eSRichard Henderson tcg_temp_free_i64(val); 292754e96c74SPeter Maydell return true; 292854e96c74SPeter Maydell } 29299aaa23c2SPeter Maydell 29309aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 29319aaa23c2SPeter Maydell { 29329aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 29339aaa23c2SPeter Maydell return false; 29349aaa23c2SPeter Maydell } 29359aaa23c2SPeter Maydell 29369aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 29379aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 29389aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 29399aaa23c2SPeter Maydell return false; 29409aaa23c2SPeter Maydell } 29419aaa23c2SPeter Maydell 29429aaa23c2SPeter Maydell if (a->vd & a->q) { 29439aaa23c2SPeter Maydell return false; 29449aaa23c2SPeter Maydell } 29459aaa23c2SPeter Maydell 29469aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 29479aaa23c2SPeter Maydell return true; 29489aaa23c2SPeter Maydell } 29499aaa23c2SPeter Maydell 2950015ee81aSRichard Henderson tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd), 29519aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 29529aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 29539aaa23c2SPeter Maydell return true; 29549aaa23c2SPeter Maydell } 2955353d2b85SPeter Maydell 2956353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 2957353d2b85SPeter Maydell { 2958353d2b85SPeter Maydell int pass, half; 2959a712266fSRichard Henderson TCGv_i32 tmp[2]; 2960353d2b85SPeter Maydell 2961353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2962353d2b85SPeter Maydell return false; 2963353d2b85SPeter Maydell } 2964353d2b85SPeter Maydell 2965353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2966353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2967353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 2968353d2b85SPeter Maydell return false; 2969353d2b85SPeter Maydell } 2970353d2b85SPeter Maydell 2971353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 2972353d2b85SPeter Maydell return false; 2973353d2b85SPeter Maydell } 2974353d2b85SPeter Maydell 2975353d2b85SPeter Maydell if (a->size == 3) { 2976353d2b85SPeter Maydell return false; 2977353d2b85SPeter Maydell } 2978353d2b85SPeter Maydell 2979353d2b85SPeter Maydell if (!vfp_access_check(s)) { 2980353d2b85SPeter Maydell return true; 2981353d2b85SPeter Maydell } 2982353d2b85SPeter Maydell 2983a712266fSRichard Henderson tmp[0] = tcg_temp_new_i32(); 2984a712266fSRichard Henderson tmp[1] = tcg_temp_new_i32(); 2985353d2b85SPeter Maydell 2986a712266fSRichard Henderson for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 2987353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 2988a712266fSRichard Henderson read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32); 2989353d2b85SPeter Maydell switch (a->size) { 2990353d2b85SPeter Maydell case 0: 2991353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 2992353d2b85SPeter Maydell break; 2993353d2b85SPeter Maydell case 1: 29948ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 2995353d2b85SPeter Maydell break; 2996353d2b85SPeter Maydell case 2: 2997353d2b85SPeter Maydell break; 2998353d2b85SPeter Maydell default: 2999353d2b85SPeter Maydell g_assert_not_reached(); 3000353d2b85SPeter Maydell } 3001353d2b85SPeter Maydell } 3002a712266fSRichard Henderson write_neon_element32(tmp[1], a->vd, pass * 2, MO_32); 3003a712266fSRichard Henderson write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32); 3004353d2b85SPeter Maydell } 3005a712266fSRichard Henderson 3006a712266fSRichard Henderson tcg_temp_free_i32(tmp[0]); 3007a712266fSRichard Henderson tcg_temp_free_i32(tmp[1]); 3008353d2b85SPeter Maydell return true; 3009353d2b85SPeter Maydell } 30106106af3aSPeter Maydell 30116106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 30126106af3aSPeter Maydell NeonGenWidenFn *widenfn, 30136106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 30146106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 30156106af3aSPeter Maydell { 30166106af3aSPeter Maydell /* 30176106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 30186106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 30196106af3aSPeter Maydell * into the destination with the accfn. 30206106af3aSPeter Maydell */ 30216106af3aSPeter Maydell int pass; 30226106af3aSPeter Maydell 30236106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30246106af3aSPeter Maydell return false; 30256106af3aSPeter Maydell } 30266106af3aSPeter Maydell 30276106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 30286106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 30296106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 30306106af3aSPeter Maydell return false; 30316106af3aSPeter Maydell } 30326106af3aSPeter Maydell 30336106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 30346106af3aSPeter Maydell return false; 30356106af3aSPeter Maydell } 30366106af3aSPeter Maydell 30376106af3aSPeter Maydell if (!widenfn) { 30386106af3aSPeter Maydell return false; 30396106af3aSPeter Maydell } 30406106af3aSPeter Maydell 30416106af3aSPeter Maydell if (!vfp_access_check(s)) { 30426106af3aSPeter Maydell return true; 30436106af3aSPeter Maydell } 30446106af3aSPeter Maydell 30456106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 30466106af3aSPeter Maydell TCGv_i32 tmp; 30476106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 30486106af3aSPeter Maydell 30496106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 30506106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 30516106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 3052a712266fSRichard Henderson 3053a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3054a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2, MO_32); 30556106af3aSPeter Maydell widenfn(rm0_64, tmp); 3056a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32); 30576106af3aSPeter Maydell widenfn(rm1_64, tmp); 30586106af3aSPeter Maydell tcg_temp_free_i32(tmp); 3059a712266fSRichard Henderson 30606106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 30616106af3aSPeter Maydell tcg_temp_free_i64(rm0_64); 30626106af3aSPeter Maydell tcg_temp_free_i64(rm1_64); 30636106af3aSPeter Maydell 30646106af3aSPeter Maydell if (accfn) { 30656106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 30660aa8e700SRichard Henderson read_neon_element64(tmp64, a->vd, pass, MO_64); 30676106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 30686106af3aSPeter Maydell tcg_temp_free_i64(tmp64); 30696106af3aSPeter Maydell } 30700aa8e700SRichard Henderson write_neon_element64(rd_64, a->vd, pass, MO_64); 30716106af3aSPeter Maydell tcg_temp_free_i64(rd_64); 30726106af3aSPeter Maydell } 30736106af3aSPeter Maydell return true; 30746106af3aSPeter Maydell } 30756106af3aSPeter Maydell 30766106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 30776106af3aSPeter Maydell { 30786106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30796106af3aSPeter Maydell gen_helper_neon_widen_s8, 30806106af3aSPeter Maydell gen_helper_neon_widen_s16, 30816106af3aSPeter Maydell tcg_gen_ext_i32_i64, 30826106af3aSPeter Maydell NULL, 30836106af3aSPeter Maydell }; 30846106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30856106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30866106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30876106af3aSPeter Maydell tcg_gen_add_i64, 30886106af3aSPeter Maydell NULL, 30896106af3aSPeter Maydell }; 30906106af3aSPeter Maydell 30916106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 30926106af3aSPeter Maydell } 30936106af3aSPeter Maydell 30946106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 30956106af3aSPeter Maydell { 30966106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30976106af3aSPeter Maydell gen_helper_neon_widen_u8, 30986106af3aSPeter Maydell gen_helper_neon_widen_u16, 30996106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31006106af3aSPeter Maydell NULL, 31016106af3aSPeter Maydell }; 31026106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31036106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31046106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31056106af3aSPeter Maydell tcg_gen_add_i64, 31066106af3aSPeter Maydell NULL, 31076106af3aSPeter Maydell }; 31086106af3aSPeter Maydell 31096106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 31106106af3aSPeter Maydell } 31116106af3aSPeter Maydell 31126106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 31136106af3aSPeter Maydell { 31146106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31156106af3aSPeter Maydell gen_helper_neon_widen_s8, 31166106af3aSPeter Maydell gen_helper_neon_widen_s16, 31176106af3aSPeter Maydell tcg_gen_ext_i32_i64, 31186106af3aSPeter Maydell NULL, 31196106af3aSPeter Maydell }; 31206106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31216106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31226106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31236106af3aSPeter Maydell tcg_gen_add_i64, 31246106af3aSPeter Maydell NULL, 31256106af3aSPeter Maydell }; 31266106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31276106af3aSPeter Maydell gen_helper_neon_addl_u16, 31286106af3aSPeter Maydell gen_helper_neon_addl_u32, 31296106af3aSPeter Maydell tcg_gen_add_i64, 31306106af3aSPeter Maydell NULL, 31316106af3aSPeter Maydell }; 31326106af3aSPeter Maydell 31336106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31346106af3aSPeter Maydell accfn[a->size]); 31356106af3aSPeter Maydell } 31366106af3aSPeter Maydell 31376106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 31386106af3aSPeter Maydell { 31396106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31406106af3aSPeter Maydell gen_helper_neon_widen_u8, 31416106af3aSPeter Maydell gen_helper_neon_widen_u16, 31426106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31436106af3aSPeter Maydell NULL, 31446106af3aSPeter Maydell }; 31456106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31466106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31476106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31486106af3aSPeter Maydell tcg_gen_add_i64, 31496106af3aSPeter Maydell NULL, 31506106af3aSPeter Maydell }; 31516106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31526106af3aSPeter Maydell gen_helper_neon_addl_u16, 31536106af3aSPeter Maydell gen_helper_neon_addl_u32, 31546106af3aSPeter Maydell tcg_gen_add_i64, 31556106af3aSPeter Maydell NULL, 31566106af3aSPeter Maydell }; 31576106af3aSPeter Maydell 31586106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31596106af3aSPeter Maydell accfn[a->size]); 31606106af3aSPeter Maydell } 3161567663a2SPeter Maydell 3162567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3163567663a2SPeter Maydell 3164567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3165567663a2SPeter Maydell ZipFn *fn) 3166567663a2SPeter Maydell { 3167567663a2SPeter Maydell TCGv_ptr pd, pm; 3168567663a2SPeter Maydell 3169567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3170567663a2SPeter Maydell return false; 3171567663a2SPeter Maydell } 3172567663a2SPeter Maydell 3173567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3174567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3175567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3176567663a2SPeter Maydell return false; 3177567663a2SPeter Maydell } 3178567663a2SPeter Maydell 3179567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3180567663a2SPeter Maydell return false; 3181567663a2SPeter Maydell } 3182567663a2SPeter Maydell 3183567663a2SPeter Maydell if (!fn) { 3184567663a2SPeter Maydell /* Bad size or size/q combination */ 3185567663a2SPeter Maydell return false; 3186567663a2SPeter Maydell } 3187567663a2SPeter Maydell 3188567663a2SPeter Maydell if (!vfp_access_check(s)) { 3189567663a2SPeter Maydell return true; 3190567663a2SPeter Maydell } 3191567663a2SPeter Maydell 3192567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3193567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3194567663a2SPeter Maydell fn(pd, pm); 3195567663a2SPeter Maydell tcg_temp_free_ptr(pd); 3196567663a2SPeter Maydell tcg_temp_free_ptr(pm); 3197567663a2SPeter Maydell return true; 3198567663a2SPeter Maydell } 3199567663a2SPeter Maydell 3200567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3201567663a2SPeter Maydell { 3202567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3203567663a2SPeter Maydell { 3204567663a2SPeter Maydell gen_helper_neon_unzip8, 3205567663a2SPeter Maydell gen_helper_neon_unzip16, 3206567663a2SPeter Maydell NULL, 3207567663a2SPeter Maydell NULL, 3208567663a2SPeter Maydell }, { 3209567663a2SPeter Maydell gen_helper_neon_qunzip8, 3210567663a2SPeter Maydell gen_helper_neon_qunzip16, 3211567663a2SPeter Maydell gen_helper_neon_qunzip32, 3212567663a2SPeter Maydell NULL, 3213567663a2SPeter Maydell } 3214567663a2SPeter Maydell }; 3215567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3216567663a2SPeter Maydell } 3217567663a2SPeter Maydell 3218567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3219567663a2SPeter Maydell { 3220567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3221567663a2SPeter Maydell { 3222567663a2SPeter Maydell gen_helper_neon_zip8, 3223567663a2SPeter Maydell gen_helper_neon_zip16, 3224567663a2SPeter Maydell NULL, 3225567663a2SPeter Maydell NULL, 3226567663a2SPeter Maydell }, { 3227567663a2SPeter Maydell gen_helper_neon_qzip8, 3228567663a2SPeter Maydell gen_helper_neon_qzip16, 3229567663a2SPeter Maydell gen_helper_neon_qzip32, 3230567663a2SPeter Maydell NULL, 3231567663a2SPeter Maydell } 3232567663a2SPeter Maydell }; 3233567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3234567663a2SPeter Maydell } 32353882bdacSPeter Maydell 32363882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 32373882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 32383882bdacSPeter Maydell { 32393882bdacSPeter Maydell TCGv_i64 rm; 32403882bdacSPeter Maydell TCGv_i32 rd0, rd1; 32413882bdacSPeter Maydell 32423882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 32433882bdacSPeter Maydell return false; 32443882bdacSPeter Maydell } 32453882bdacSPeter Maydell 32463882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 32473882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 32483882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 32493882bdacSPeter Maydell return false; 32503882bdacSPeter Maydell } 32513882bdacSPeter Maydell 32523882bdacSPeter Maydell if (a->vm & 1) { 32533882bdacSPeter Maydell return false; 32543882bdacSPeter Maydell } 32553882bdacSPeter Maydell 32563882bdacSPeter Maydell if (!narrowfn) { 32573882bdacSPeter Maydell return false; 32583882bdacSPeter Maydell } 32593882bdacSPeter Maydell 32603882bdacSPeter Maydell if (!vfp_access_check(s)) { 32613882bdacSPeter Maydell return true; 32623882bdacSPeter Maydell } 32633882bdacSPeter Maydell 32643882bdacSPeter Maydell rm = tcg_temp_new_i64(); 32653882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 32663882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 32673882bdacSPeter Maydell 32680aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 0, MO_64); 32693882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 32700aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 1, MO_64); 32713882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 3272a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 3273a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 3274a712266fSRichard Henderson tcg_temp_free_i32(rd0); 3275a712266fSRichard Henderson tcg_temp_free_i32(rd1); 32763882bdacSPeter Maydell tcg_temp_free_i64(rm); 32773882bdacSPeter Maydell return true; 32783882bdacSPeter Maydell } 32793882bdacSPeter Maydell 32803882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 32813882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 32823882bdacSPeter Maydell { \ 32833882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 32843882bdacSPeter Maydell FUNC##8, \ 32853882bdacSPeter Maydell FUNC##16, \ 32863882bdacSPeter Maydell FUNC##32, \ 32873882bdacSPeter Maydell NULL, \ 32883882bdacSPeter Maydell }; \ 32893882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 32903882bdacSPeter Maydell } 32913882bdacSPeter Maydell 32923882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 32933882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 32943882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 32953882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3296749e2be3SPeter Maydell 3297749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3298749e2be3SPeter Maydell { 3299749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3300749e2be3SPeter Maydell TCGv_i64 rd; 3301749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3302749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3303749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3304749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3305749e2be3SPeter Maydell NULL, 3306749e2be3SPeter Maydell }; 3307749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3308749e2be3SPeter Maydell 3309749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3310749e2be3SPeter Maydell return false; 3311749e2be3SPeter Maydell } 3312749e2be3SPeter Maydell 3313749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3314749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3315749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3316749e2be3SPeter Maydell return false; 3317749e2be3SPeter Maydell } 3318749e2be3SPeter Maydell 3319749e2be3SPeter Maydell if (a->vd & 1) { 3320749e2be3SPeter Maydell return false; 3321749e2be3SPeter Maydell } 3322749e2be3SPeter Maydell 3323749e2be3SPeter Maydell if (!widenfn) { 3324749e2be3SPeter Maydell return false; 3325749e2be3SPeter Maydell } 3326749e2be3SPeter Maydell 3327749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3328749e2be3SPeter Maydell return true; 3329749e2be3SPeter Maydell } 3330749e2be3SPeter Maydell 3331749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3332a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 3333a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 3334749e2be3SPeter Maydell 3335a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 3336a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 3337749e2be3SPeter Maydell 3338749e2be3SPeter Maydell widenfn(rd, rm0); 3339749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 33400aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 0, MO_64); 3341749e2be3SPeter Maydell widenfn(rd, rm1); 3342749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 33430aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 1, MO_64); 3344749e2be3SPeter Maydell 3345749e2be3SPeter Maydell tcg_temp_free_i64(rd); 3346749e2be3SPeter Maydell tcg_temp_free_i32(rm0); 3347749e2be3SPeter Maydell tcg_temp_free_i32(rm1); 3348749e2be3SPeter Maydell return true; 3349749e2be3SPeter Maydell } 3350654a5173SPeter Maydell 3351d29b17caSRichard Henderson static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a) 3352d29b17caSRichard Henderson { 3353d29b17caSRichard Henderson TCGv_ptr fpst; 3354d29b17caSRichard Henderson TCGv_i64 tmp; 3355d29b17caSRichard Henderson TCGv_i32 dst0, dst1; 3356d29b17caSRichard Henderson 3357d29b17caSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 3358d29b17caSRichard Henderson return false; 3359d29b17caSRichard Henderson } 3360d29b17caSRichard Henderson 3361d29b17caSRichard Henderson /* UNDEF accesses to D16-D31 if they don't exist. */ 3362d29b17caSRichard Henderson if (!dc_isar_feature(aa32_simd_r32, s) && 3363d29b17caSRichard Henderson ((a->vd | a->vm) & 0x10)) { 3364d29b17caSRichard Henderson return false; 3365d29b17caSRichard Henderson } 3366d29b17caSRichard Henderson 3367d29b17caSRichard Henderson if ((a->vm & 1) || (a->size != 1)) { 3368d29b17caSRichard Henderson return false; 3369d29b17caSRichard Henderson } 3370d29b17caSRichard Henderson 3371d29b17caSRichard Henderson if (!vfp_access_check(s)) { 3372d29b17caSRichard Henderson return true; 3373d29b17caSRichard Henderson } 3374d29b17caSRichard Henderson 3375d29b17caSRichard Henderson fpst = fpstatus_ptr(FPST_STD); 3376d29b17caSRichard Henderson tmp = tcg_temp_new_i64(); 3377d29b17caSRichard Henderson dst0 = tcg_temp_new_i32(); 3378d29b17caSRichard Henderson dst1 = tcg_temp_new_i32(); 3379d29b17caSRichard Henderson 3380d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 0, MO_64); 3381d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst0, tmp, fpst); 3382d29b17caSRichard Henderson 3383d29b17caSRichard Henderson read_neon_element64(tmp, a->vm, 1, MO_64); 3384d29b17caSRichard Henderson gen_helper_bfcvt_pair(dst1, tmp, fpst); 3385d29b17caSRichard Henderson 3386d29b17caSRichard Henderson write_neon_element32(dst0, a->vd, 0, MO_32); 3387d29b17caSRichard Henderson write_neon_element32(dst1, a->vd, 1, MO_32); 3388d29b17caSRichard Henderson 3389d29b17caSRichard Henderson tcg_temp_free_i64(tmp); 3390d29b17caSRichard Henderson tcg_temp_free_i32(dst0); 3391d29b17caSRichard Henderson tcg_temp_free_i32(dst1); 3392d29b17caSRichard Henderson tcg_temp_free_ptr(fpst); 3393d29b17caSRichard Henderson return true; 3394d29b17caSRichard Henderson } 3395d29b17caSRichard Henderson 3396654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3397654a5173SPeter Maydell { 3398654a5173SPeter Maydell TCGv_ptr fpst; 3399654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3400654a5173SPeter Maydell 3401654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3402654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3403654a5173SPeter Maydell return false; 3404654a5173SPeter Maydell } 3405654a5173SPeter Maydell 3406654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3407654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3408654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3409654a5173SPeter Maydell return false; 3410654a5173SPeter Maydell } 3411654a5173SPeter Maydell 3412654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3413654a5173SPeter Maydell return false; 3414654a5173SPeter Maydell } 3415654a5173SPeter Maydell 3416654a5173SPeter Maydell if (!vfp_access_check(s)) { 3417654a5173SPeter Maydell return true; 3418654a5173SPeter Maydell } 3419654a5173SPeter Maydell 3420a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3421654a5173SPeter Maydell ahp = get_ahp_flag(); 3422a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3423a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3424654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3425a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3426a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3427654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3428654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3429654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3430a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 2, MO_32); 3431654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3432a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 3433a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 3, MO_32); 3434a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 0, MO_32); 3435a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3436654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3437654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3438654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3439a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 3440a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3441654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3442654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3443654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3444654a5173SPeter Maydell 3445654a5173SPeter Maydell return true; 3446654a5173SPeter Maydell } 3447654a5173SPeter Maydell 3448654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3449654a5173SPeter Maydell { 3450654a5173SPeter Maydell TCGv_ptr fpst; 3451654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3452654a5173SPeter Maydell 3453654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3454654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3455654a5173SPeter Maydell return false; 3456654a5173SPeter Maydell } 3457654a5173SPeter Maydell 3458654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3459654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3460654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3461654a5173SPeter Maydell return false; 3462654a5173SPeter Maydell } 3463654a5173SPeter Maydell 3464654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3465654a5173SPeter Maydell return false; 3466654a5173SPeter Maydell } 3467654a5173SPeter Maydell 3468654a5173SPeter Maydell if (!vfp_access_check(s)) { 3469654a5173SPeter Maydell return true; 3470654a5173SPeter Maydell } 3471654a5173SPeter Maydell 3472a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3473654a5173SPeter Maydell ahp = get_ahp_flag(); 3474654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3475a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3476a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3477a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3478a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3479654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3480654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3481a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 0, MO_32); 3482654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3483654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3484a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 1, MO_32); 3485a712266fSRichard Henderson tcg_temp_free_i32(tmp); 3486654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3487654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3488a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 2, MO_32); 3489a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3490654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3491654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3492a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 3, MO_32); 3493a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3494654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3495654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3496654a5173SPeter Maydell 3497654a5173SPeter Maydell return true; 3498654a5173SPeter Maydell } 349975153179SPeter Maydell 350075153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 350175153179SPeter Maydell { 350275153179SPeter Maydell int vec_size = a->q ? 16 : 8; 3503015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 3504015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 350575153179SPeter Maydell 350675153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 350775153179SPeter Maydell return false; 350875153179SPeter Maydell } 350975153179SPeter Maydell 351075153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 351175153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 351275153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 351375153179SPeter Maydell return false; 351475153179SPeter Maydell } 351575153179SPeter Maydell 351675153179SPeter Maydell if (a->size == 3) { 351775153179SPeter Maydell return false; 351875153179SPeter Maydell } 351975153179SPeter Maydell 352075153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 352175153179SPeter Maydell return false; 352275153179SPeter Maydell } 352375153179SPeter Maydell 352475153179SPeter Maydell if (!vfp_access_check(s)) { 352575153179SPeter Maydell return true; 352675153179SPeter Maydell } 352775153179SPeter Maydell 352875153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 352975153179SPeter Maydell 353075153179SPeter Maydell return true; 353175153179SPeter Maydell } 353275153179SPeter Maydell 353375153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 353475153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 353575153179SPeter Maydell { \ 353675153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 353775153179SPeter Maydell } 353875153179SPeter Maydell 353975153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 354075153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 354175153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 354275153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 354375153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 354475153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 354575153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 354675153179SPeter Maydell 354775153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 354875153179SPeter Maydell { 354975153179SPeter Maydell if (a->size != 0) { 355075153179SPeter Maydell return false; 355175153179SPeter Maydell } 355275153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 355375153179SPeter Maydell } 35540b30dd5bSPeter Maydell 35550b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 35560b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35570b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35580b30dd5bSPeter Maydell uint32_t maxsz) \ 35590b30dd5bSPeter Maydell { \ 35600b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 35610b30dd5bSPeter Maydell DATA, FUNC); \ 35620b30dd5bSPeter Maydell } 35630b30dd5bSPeter Maydell 35640b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 35650b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35660b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35670b30dd5bSPeter Maydell uint32_t maxsz) \ 35680b30dd5bSPeter Maydell { \ 35690b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 35700b30dd5bSPeter Maydell } 35710b30dd5bSPeter Maydell 35720b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 35730b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 35740b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 35750b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 35760b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 35770b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 35780b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 35790b30dd5bSPeter Maydell 35800b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 35810b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 35820b30dd5bSPeter Maydell { \ 35830b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 35840b30dd5bSPeter Maydell return false; \ 35850b30dd5bSPeter Maydell } \ 35860b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 35870b30dd5bSPeter Maydell } 35880b30dd5bSPeter Maydell 35890b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 35900b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 35910b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 35920b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 35930b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 35940b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 35950b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 359689668082SPeter Maydell 359789668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 359889668082SPeter Maydell { 3599a712266fSRichard Henderson TCGv_i32 tmp; 360089668082SPeter Maydell int pass; 360189668082SPeter Maydell 360289668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 360389668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 360489668082SPeter Maydell return false; 360589668082SPeter Maydell } 360689668082SPeter Maydell 360789668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 360889668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 360989668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 361089668082SPeter Maydell return false; 361189668082SPeter Maydell } 361289668082SPeter Maydell 361389668082SPeter Maydell if (!fn) { 361489668082SPeter Maydell return false; 361589668082SPeter Maydell } 361689668082SPeter Maydell 361789668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 361889668082SPeter Maydell return false; 361989668082SPeter Maydell } 362089668082SPeter Maydell 362189668082SPeter Maydell if (!vfp_access_check(s)) { 362289668082SPeter Maydell return true; 362389668082SPeter Maydell } 362489668082SPeter Maydell 3625a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 362689668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3627a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 362889668082SPeter Maydell fn(tmp, tmp); 3629a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 363089668082SPeter Maydell } 3631a712266fSRichard Henderson tcg_temp_free_i32(tmp); 363289668082SPeter Maydell 363389668082SPeter Maydell return true; 363489668082SPeter Maydell } 363589668082SPeter Maydell 363689668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 363789668082SPeter Maydell { 363889668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 363989668082SPeter Maydell tcg_gen_bswap32_i32, 364089668082SPeter Maydell gen_swap_half, 364189668082SPeter Maydell NULL, 364289668082SPeter Maydell NULL, 364389668082SPeter Maydell }; 364489668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 364589668082SPeter Maydell } 364689668082SPeter Maydell 364789668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 364889668082SPeter Maydell { 364989668082SPeter Maydell if (a->size != 0) { 365089668082SPeter Maydell return false; 365189668082SPeter Maydell } 365289668082SPeter Maydell return do_2misc(s, a, gen_rev16); 365389668082SPeter Maydell } 365484eae770SPeter Maydell 365584eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 365684eae770SPeter Maydell { 365784eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 365884eae770SPeter Maydell gen_helper_neon_cls_s8, 365984eae770SPeter Maydell gen_helper_neon_cls_s16, 366084eae770SPeter Maydell gen_helper_neon_cls_s32, 366184eae770SPeter Maydell NULL, 366284eae770SPeter Maydell }; 366384eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 366484eae770SPeter Maydell } 366584eae770SPeter Maydell 366684eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 366784eae770SPeter Maydell { 366884eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 366984eae770SPeter Maydell } 367084eae770SPeter Maydell 367184eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 367284eae770SPeter Maydell { 367384eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 367484eae770SPeter Maydell gen_helper_neon_clz_u8, 367584eae770SPeter Maydell gen_helper_neon_clz_u16, 367684eae770SPeter Maydell do_VCLZ_32, 367784eae770SPeter Maydell NULL, 367884eae770SPeter Maydell }; 367984eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 368084eae770SPeter Maydell } 368184eae770SPeter Maydell 368284eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 368384eae770SPeter Maydell { 368484eae770SPeter Maydell if (a->size != 0) { 368584eae770SPeter Maydell return false; 368684eae770SPeter Maydell } 368784eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 368884eae770SPeter Maydell } 368984eae770SPeter Maydell 36902b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 36912b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 36922b70d8cdSPeter Maydell { 36932b70d8cdSPeter Maydell tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs, 36942b70d8cdSPeter Maydell vece == MO_16 ? 0x7fff : 0x7fffffff, 36952b70d8cdSPeter Maydell oprsz, maxsz); 36962b70d8cdSPeter Maydell } 36972b70d8cdSPeter Maydell 369884eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 369984eae770SPeter Maydell { 37002b70d8cdSPeter Maydell if (a->size == MO_16) { 37012b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 370284eae770SPeter Maydell return false; 370384eae770SPeter Maydell } 37042b70d8cdSPeter Maydell } else if (a->size != MO_32) { 37052b70d8cdSPeter Maydell return false; 37062b70d8cdSPeter Maydell } 37072b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VABS_F); 37082b70d8cdSPeter Maydell } 37092b70d8cdSPeter Maydell 37102b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 37112b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 37122b70d8cdSPeter Maydell { 37132b70d8cdSPeter Maydell tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs, 37142b70d8cdSPeter Maydell vece == MO_16 ? 0x8000 : 0x80000000, 37152b70d8cdSPeter Maydell oprsz, maxsz); 371684eae770SPeter Maydell } 371784eae770SPeter Maydell 371884eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 371984eae770SPeter Maydell { 37202b70d8cdSPeter Maydell if (a->size == MO_16) { 37212b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 372284eae770SPeter Maydell return false; 372384eae770SPeter Maydell } 37242b70d8cdSPeter Maydell } else if (a->size != MO_32) { 37252b70d8cdSPeter Maydell return false; 37262b70d8cdSPeter Maydell } 37272b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VNEG_F); 372884eae770SPeter Maydell } 372984eae770SPeter Maydell 373084eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 373184eae770SPeter Maydell { 373284eae770SPeter Maydell if (a->size != 2) { 373384eae770SPeter Maydell return false; 373484eae770SPeter Maydell } 373584eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 373684eae770SPeter Maydell } 373784eae770SPeter Maydell 373884eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 373984eae770SPeter Maydell { 374084eae770SPeter Maydell if (a->size != 2) { 374184eae770SPeter Maydell return false; 374284eae770SPeter Maydell } 374384eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 374484eae770SPeter Maydell } 37454936f38aSPeter Maydell 37464936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 37474936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 37484936f38aSPeter Maydell { \ 37494936f38aSPeter Maydell FUNC(d, cpu_env, m); \ 37504936f38aSPeter Maydell } 37514936f38aSPeter Maydell 37524936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 37534936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 37544936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 37554936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 37564936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 37574936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 37584936f38aSPeter Maydell 37594936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 37604936f38aSPeter Maydell { 37614936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 37624936f38aSPeter Maydell gen_VQABS_s8, 37634936f38aSPeter Maydell gen_VQABS_s16, 37644936f38aSPeter Maydell gen_VQABS_s32, 37654936f38aSPeter Maydell NULL, 37664936f38aSPeter Maydell }; 37674936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 37684936f38aSPeter Maydell } 37694936f38aSPeter Maydell 37704936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 37714936f38aSPeter Maydell { 37724936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 37734936f38aSPeter Maydell gen_VQNEG_s8, 37744936f38aSPeter Maydell gen_VQNEG_s16, 37754936f38aSPeter Maydell gen_VQNEG_s32, 37764936f38aSPeter Maydell NULL, 37774936f38aSPeter Maydell }; 37784936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 37794936f38aSPeter Maydell } 37803e96b205SPeter Maydell 37814a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC) \ 37824a15d9a3SPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 37834a15d9a3SPeter Maydell uint32_t rm_ofs, \ 37844a15d9a3SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 37854a15d9a3SPeter Maydell { \ 37864a15d9a3SPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 37874a15d9a3SPeter Maydell NULL, HFUNC, SFUNC, NULL, \ 37884a15d9a3SPeter Maydell }; \ 37894a15d9a3SPeter Maydell TCGv_ptr fpst; \ 37904a15d9a3SPeter Maydell fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD); \ 37914a15d9a3SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0, \ 37924a15d9a3SPeter Maydell fns[vece]); \ 37934a15d9a3SPeter Maydell tcg_temp_free_ptr(fpst); \ 37944a15d9a3SPeter Maydell } \ 37954a15d9a3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 37964a15d9a3SPeter Maydell { \ 37974a15d9a3SPeter Maydell if (a->size == MO_16) { \ 37984a15d9a3SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 37994a15d9a3SPeter Maydell return false; \ 38004a15d9a3SPeter Maydell } \ 38014a15d9a3SPeter Maydell } else if (a->size != MO_32) { \ 38024a15d9a3SPeter Maydell return false; \ 38034a15d9a3SPeter Maydell } \ 38044a15d9a3SPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 38054a15d9a3SPeter Maydell } 38064a15d9a3SPeter Maydell 38074a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s) 38084a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s) 3809635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s) 3810635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s) 3811635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s) 3812635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s) 3813635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s) 38147782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos) 38157782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos) 38167782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs) 38177782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs) 38184a15d9a3SPeter Maydell 381923afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s) 382023afcdd2SPeter Maydell 38213e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 38223e96b205SPeter Maydell { 38233e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 38243e96b205SPeter Maydell return false; 38253e96b205SPeter Maydell } 382623afcdd2SPeter Maydell return trans_VRINTX_impl(s, a); 38273e96b205SPeter Maydell } 3828baa59323SPeter Maydell 3829ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP) \ 3830ca88a6efSPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 3831ca88a6efSPeter Maydell uint32_t rm_ofs, \ 3832ca88a6efSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 3833ca88a6efSPeter Maydell { \ 3834ca88a6efSPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 3835ca88a6efSPeter Maydell NULL, \ 3836ca88a6efSPeter Maydell gen_helper_gvec_##OP##h, \ 3837ca88a6efSPeter Maydell gen_helper_gvec_##OP##s, \ 3838ca88a6efSPeter Maydell NULL, \ 3839ca88a6efSPeter Maydell }; \ 3840ca88a6efSPeter Maydell TCGv_ptr fpst; \ 3841ca88a6efSPeter Maydell fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD); \ 3842ca88a6efSPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, \ 3843ca88a6efSPeter Maydell arm_rmode_to_sf(RMODE), fns[vece]); \ 3844ca88a6efSPeter Maydell tcg_temp_free_ptr(fpst); \ 3845ca88a6efSPeter Maydell } \ 3846a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3847a183d5fbSPeter Maydell { \ 3848ca88a6efSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { \ 3849ca88a6efSPeter Maydell return false; \ 3850ca88a6efSPeter Maydell } \ 3851ca88a6efSPeter Maydell if (a->size == MO_16) { \ 3852ca88a6efSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 3853ca88a6efSPeter Maydell return false; \ 3854ca88a6efSPeter Maydell } \ 3855ca88a6efSPeter Maydell } else if (a->size != MO_32) { \ 3856ca88a6efSPeter Maydell return false; \ 3857ca88a6efSPeter Maydell } \ 3858ca88a6efSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 3859a183d5fbSPeter Maydell } 3860a183d5fbSPeter Maydell 3861ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u) 3862ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s) 3863ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u) 3864ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s) 3865ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u) 3866ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s) 3867ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u) 3868ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s) 38698ab3a227SPeter Maydell 387018725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_) 387118725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_) 387218725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_) 387318725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_) 387418725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_) 387518725916SPeter Maydell 38768ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 38778ab3a227SPeter Maydell { 38788ab3a227SPeter Maydell TCGv_i64 rm, rd; 38798ab3a227SPeter Maydell int pass; 38808ab3a227SPeter Maydell 38818ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 38828ab3a227SPeter Maydell return false; 38838ab3a227SPeter Maydell } 38848ab3a227SPeter Maydell 38858ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 38868ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 38878ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 38888ab3a227SPeter Maydell return false; 38898ab3a227SPeter Maydell } 38908ab3a227SPeter Maydell 38918ab3a227SPeter Maydell if (a->size != 0) { 38928ab3a227SPeter Maydell return false; 38938ab3a227SPeter Maydell } 38948ab3a227SPeter Maydell 38958ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 38968ab3a227SPeter Maydell return false; 38978ab3a227SPeter Maydell } 38988ab3a227SPeter Maydell 38998ab3a227SPeter Maydell if (!vfp_access_check(s)) { 39008ab3a227SPeter Maydell return true; 39018ab3a227SPeter Maydell } 39028ab3a227SPeter Maydell 39038ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 39048ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 39058ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 39060aa8e700SRichard Henderson read_neon_element64(rm, a->vm, pass, MO_64); 39070aa8e700SRichard Henderson read_neon_element64(rd, a->vd, pass, MO_64); 39080aa8e700SRichard Henderson write_neon_element64(rm, a->vd, pass, MO_64); 39090aa8e700SRichard Henderson write_neon_element64(rd, a->vm, pass, MO_64); 39108ab3a227SPeter Maydell } 39118ab3a227SPeter Maydell tcg_temp_free_i64(rm); 39128ab3a227SPeter Maydell tcg_temp_free_i64(rd); 39138ab3a227SPeter Maydell 39148ab3a227SPeter Maydell return true; 39158ab3a227SPeter Maydell } 3916d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 3917d4366190SPeter Maydell { 3918d4366190SPeter Maydell TCGv_i32 rd, tmp; 3919d4366190SPeter Maydell 3920d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3921d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3922d4366190SPeter Maydell 3923d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 3924d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 3925d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 3926d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3927d4366190SPeter Maydell 3928d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 3929d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 3930d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 3931d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3932d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3933d4366190SPeter Maydell 3934d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3935d4366190SPeter Maydell tcg_temp_free_i32(rd); 3936d4366190SPeter Maydell } 3937d4366190SPeter Maydell 3938d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 3939d4366190SPeter Maydell { 3940d4366190SPeter Maydell TCGv_i32 rd, tmp; 3941d4366190SPeter Maydell 3942d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3943d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3944d4366190SPeter Maydell 3945d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 3946d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 3947d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3948d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 3949d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 3950d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3951d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3952d4366190SPeter Maydell 3953d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3954d4366190SPeter Maydell tcg_temp_free_i32(rd); 3955d4366190SPeter Maydell } 3956d4366190SPeter Maydell 3957d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 3958d4366190SPeter Maydell { 3959d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 3960d4366190SPeter Maydell int pass; 3961d4366190SPeter Maydell 3962d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3963d4366190SPeter Maydell return false; 3964d4366190SPeter Maydell } 3965d4366190SPeter Maydell 3966d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3967d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3968d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3969d4366190SPeter Maydell return false; 3970d4366190SPeter Maydell } 3971d4366190SPeter Maydell 3972d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 3973d4366190SPeter Maydell return false; 3974d4366190SPeter Maydell } 3975d4366190SPeter Maydell 3976d4366190SPeter Maydell if (a->size == 3) { 3977d4366190SPeter Maydell return false; 3978d4366190SPeter Maydell } 3979d4366190SPeter Maydell 3980d4366190SPeter Maydell if (!vfp_access_check(s)) { 3981d4366190SPeter Maydell return true; 3982d4366190SPeter Maydell } 3983d4366190SPeter Maydell 3984a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3985a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3986a712266fSRichard Henderson if (a->size == MO_32) { 3987d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 3988a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3989a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass + 1, MO_32); 3990a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3991a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass + 1, MO_32); 3992d4366190SPeter Maydell } 3993d4366190SPeter Maydell } else { 3994d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3995a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3996a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass, MO_32); 3997a712266fSRichard Henderson if (a->size == MO_8) { 3998d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 3999d4366190SPeter Maydell } else { 4000d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 4001d4366190SPeter Maydell } 4002a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 4003a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 4004d4366190SPeter Maydell } 4005d4366190SPeter Maydell } 4006a712266fSRichard Henderson tcg_temp_free_i32(tmp); 4007a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 4008d4366190SPeter Maydell return true; 4009d4366190SPeter Maydell } 40102323c5ffSRichard Henderson 40112323c5ffSRichard Henderson static bool trans_VSMMLA(DisasContext *s, arg_VSMMLA *a) 40122323c5ffSRichard Henderson { 40132323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 40142323c5ffSRichard Henderson return false; 40152323c5ffSRichard Henderson } 40162323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 40172323c5ffSRichard Henderson gen_helper_gvec_smmla_b); 40182323c5ffSRichard Henderson } 40192323c5ffSRichard Henderson 40202323c5ffSRichard Henderson static bool trans_VUMMLA(DisasContext *s, arg_VUMMLA *a) 40212323c5ffSRichard Henderson { 40222323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 40232323c5ffSRichard Henderson return false; 40242323c5ffSRichard Henderson } 40252323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 40262323c5ffSRichard Henderson gen_helper_gvec_ummla_b); 40272323c5ffSRichard Henderson } 40282323c5ffSRichard Henderson 40292323c5ffSRichard Henderson static bool trans_VUSMMLA(DisasContext *s, arg_VUSMMLA *a) 40302323c5ffSRichard Henderson { 40312323c5ffSRichard Henderson if (!dc_isar_feature(aa32_i8mm, s)) { 40322323c5ffSRichard Henderson return false; 40332323c5ffSRichard Henderson } 40342323c5ffSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 40352323c5ffSRichard Henderson gen_helper_gvec_usmmla_b); 40362323c5ffSRichard Henderson } 403781266a1fSRichard Henderson 403881266a1fSRichard Henderson static bool trans_VMMLA_b16(DisasContext *s, arg_VMMLA_b16 *a) 403981266a1fSRichard Henderson { 404081266a1fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 404181266a1fSRichard Henderson return false; 404281266a1fSRichard Henderson } 404381266a1fSRichard Henderson return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0, 404481266a1fSRichard Henderson gen_helper_gvec_bfmmla); 404581266a1fSRichard Henderson } 40465693887fSRichard Henderson 40475693887fSRichard Henderson static bool trans_VFMA_b16(DisasContext *s, arg_VFMA_b16 *a) 40485693887fSRichard Henderson { 40495693887fSRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 40505693887fSRichard Henderson return false; 40515693887fSRichard Henderson } 40525693887fSRichard Henderson return do_neon_ddda_fpst(s, 7, a->vd, a->vn, a->vm, a->q, FPST_STD, 40535693887fSRichard Henderson gen_helper_gvec_bfmlal); 40545693887fSRichard Henderson } 4055458d0ab6SRichard Henderson 4056458d0ab6SRichard Henderson static bool trans_VFMA_b16_scal(DisasContext *s, arg_VFMA_b16_scal *a) 4057458d0ab6SRichard Henderson { 4058458d0ab6SRichard Henderson if (!dc_isar_feature(aa32_bf16, s)) { 4059458d0ab6SRichard Henderson return false; 4060458d0ab6SRichard Henderson } 4061458d0ab6SRichard Henderson return do_neon_ddda_fpst(s, 6, a->vd, a->vn, a->vm, 4062458d0ab6SRichard Henderson (a->index << 1) | a->q, FPST_STD, 4063458d0ab6SRichard Henderson gen_helper_gvec_bfmlal_idx); 4064458d0ab6SRichard Henderson } 4065