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 12625e3dd4SPeter Maydell * version 2 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 23625e3dd4SPeter Maydell /* 24625e3dd4SPeter Maydell * This file is intended to be included from translate.c; it uses 25625e3dd4SPeter Maydell * some macros and definitions provided by that file. 26625e3dd4SPeter Maydell * It might be possible to convert it to a standalone .c file eventually. 27625e3dd4SPeter Maydell */ 28625e3dd4SPeter Maydell 29123ce4e3SPeter Maydell static inline int plus1(DisasContext *s, int x) 30123ce4e3SPeter Maydell { 31123ce4e3SPeter Maydell return x + 1; 32123ce4e3SPeter Maydell } 33123ce4e3SPeter Maydell 3466432d6bSPeter Maydell static inline int rsub_64(DisasContext *s, int x) 3566432d6bSPeter Maydell { 3666432d6bSPeter Maydell return 64 - x; 3766432d6bSPeter Maydell } 3866432d6bSPeter Maydell 3966432d6bSPeter Maydell static inline int rsub_32(DisasContext *s, int x) 4066432d6bSPeter Maydell { 4166432d6bSPeter Maydell return 32 - x; 4266432d6bSPeter Maydell } 4366432d6bSPeter Maydell static inline int rsub_16(DisasContext *s, int x) 4466432d6bSPeter Maydell { 4566432d6bSPeter Maydell return 16 - x; 4666432d6bSPeter Maydell } 4766432d6bSPeter Maydell static inline int rsub_8(DisasContext *s, int x) 4866432d6bSPeter Maydell { 4966432d6bSPeter Maydell return 8 - x; 5066432d6bSPeter Maydell } 5166432d6bSPeter Maydell 52625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 53139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc" 54139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc" 55139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc" 56afff8de0SPeter Maydell 576fb57878SPeter Maydell /* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, 586fb57878SPeter Maydell * where 0 is the least significant end of the register. 596fb57878SPeter Maydell */ 606fb57878SPeter Maydell static inline long 616fb57878SPeter Maydell neon_element_offset(int reg, int element, MemOp size) 626fb57878SPeter Maydell { 636fb57878SPeter Maydell int element_size = 1 << size; 646fb57878SPeter Maydell int ofs = element * element_size; 656fb57878SPeter Maydell #ifdef HOST_WORDS_BIGENDIAN 666fb57878SPeter Maydell /* Calculate the offset assuming fully little-endian, 676fb57878SPeter Maydell * then XOR to account for the order of the 8-byte units. 686fb57878SPeter Maydell */ 696fb57878SPeter Maydell if (element_size < 8) { 706fb57878SPeter Maydell ofs ^= 8 - element_size; 716fb57878SPeter Maydell } 726fb57878SPeter Maydell #endif 736fb57878SPeter Maydell return neon_reg_offset(reg, 0) + ofs; 746fb57878SPeter Maydell } 756fb57878SPeter Maydell 766fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) 776fb57878SPeter Maydell { 786fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 796fb57878SPeter Maydell 806fb57878SPeter Maydell switch (mop) { 816fb57878SPeter Maydell case MO_UB: 826fb57878SPeter Maydell tcg_gen_ld8u_i32(var, cpu_env, offset); 836fb57878SPeter Maydell break; 846fb57878SPeter Maydell case MO_UW: 856fb57878SPeter Maydell tcg_gen_ld16u_i32(var, cpu_env, offset); 866fb57878SPeter Maydell break; 876fb57878SPeter Maydell case MO_UL: 886fb57878SPeter Maydell tcg_gen_ld_i32(var, cpu_env, offset); 896fb57878SPeter Maydell break; 906fb57878SPeter Maydell default: 916fb57878SPeter Maydell g_assert_not_reached(); 926fb57878SPeter Maydell } 936fb57878SPeter Maydell } 946fb57878SPeter Maydell 956fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) 966fb57878SPeter Maydell { 976fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 986fb57878SPeter Maydell 996fb57878SPeter Maydell switch (mop) { 1006fb57878SPeter Maydell case MO_UB: 1016fb57878SPeter Maydell tcg_gen_ld8u_i64(var, cpu_env, offset); 1026fb57878SPeter Maydell break; 1036fb57878SPeter Maydell case MO_UW: 1046fb57878SPeter Maydell tcg_gen_ld16u_i64(var, cpu_env, offset); 1056fb57878SPeter Maydell break; 1066fb57878SPeter Maydell case MO_UL: 1076fb57878SPeter Maydell tcg_gen_ld32u_i64(var, cpu_env, offset); 1086fb57878SPeter Maydell break; 1096fb57878SPeter Maydell case MO_Q: 1106fb57878SPeter Maydell tcg_gen_ld_i64(var, cpu_env, offset); 1116fb57878SPeter Maydell break; 1126fb57878SPeter Maydell default: 1136fb57878SPeter Maydell g_assert_not_reached(); 1146fb57878SPeter Maydell } 1156fb57878SPeter Maydell } 1166fb57878SPeter Maydell 1176fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) 1186fb57878SPeter Maydell { 1196fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1206fb57878SPeter Maydell 1216fb57878SPeter Maydell switch (size) { 1226fb57878SPeter Maydell case MO_8: 1236fb57878SPeter Maydell tcg_gen_st8_i32(var, cpu_env, offset); 1246fb57878SPeter Maydell break; 1256fb57878SPeter Maydell case MO_16: 1266fb57878SPeter Maydell tcg_gen_st16_i32(var, cpu_env, offset); 1276fb57878SPeter Maydell break; 1286fb57878SPeter Maydell case MO_32: 1296fb57878SPeter Maydell tcg_gen_st_i32(var, cpu_env, offset); 1306fb57878SPeter Maydell break; 1316fb57878SPeter Maydell default: 1326fb57878SPeter Maydell g_assert_not_reached(); 1336fb57878SPeter Maydell } 1346fb57878SPeter Maydell } 1356fb57878SPeter Maydell 1366fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) 1376fb57878SPeter Maydell { 1386fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1396fb57878SPeter Maydell 1406fb57878SPeter Maydell switch (size) { 1416fb57878SPeter Maydell case MO_8: 1426fb57878SPeter Maydell tcg_gen_st8_i64(var, cpu_env, offset); 1436fb57878SPeter Maydell break; 1446fb57878SPeter Maydell case MO_16: 1456fb57878SPeter Maydell tcg_gen_st16_i64(var, cpu_env, offset); 1466fb57878SPeter Maydell break; 1476fb57878SPeter Maydell case MO_32: 1486fb57878SPeter Maydell tcg_gen_st32_i64(var, cpu_env, offset); 1496fb57878SPeter Maydell break; 1506fb57878SPeter Maydell case MO_64: 1516fb57878SPeter Maydell tcg_gen_st_i64(var, cpu_env, offset); 1526fb57878SPeter Maydell break; 1536fb57878SPeter Maydell default: 1546fb57878SPeter Maydell g_assert_not_reached(); 1556fb57878SPeter Maydell } 1566fb57878SPeter Maydell } 1576fb57878SPeter Maydell 158afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 159afff8de0SPeter Maydell { 160afff8de0SPeter Maydell int opr_sz; 161afff8de0SPeter Maydell TCGv_ptr fpst; 162afff8de0SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 163afff8de0SPeter Maydell 164afff8de0SPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 165afff8de0SPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 166afff8de0SPeter Maydell return false; 167afff8de0SPeter Maydell } 168afff8de0SPeter Maydell 169afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 170afff8de0SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 171afff8de0SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 172afff8de0SPeter Maydell return false; 173afff8de0SPeter Maydell } 174afff8de0SPeter Maydell 175afff8de0SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 176afff8de0SPeter Maydell return false; 177afff8de0SPeter Maydell } 178afff8de0SPeter Maydell 179afff8de0SPeter Maydell if (!vfp_access_check(s)) { 180afff8de0SPeter Maydell return true; 181afff8de0SPeter Maydell } 182afff8de0SPeter Maydell 183afff8de0SPeter Maydell opr_sz = (1 + a->q) * 8; 184b34aa512SPeter Maydell fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD); 185afff8de0SPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah; 186afff8de0SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 187afff8de0SPeter Maydell vfp_reg_offset(1, a->vn), 188afff8de0SPeter Maydell vfp_reg_offset(1, a->vm), 189afff8de0SPeter Maydell fpst, opr_sz, opr_sz, a->rot, 190afff8de0SPeter Maydell fn_gvec_ptr); 191afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 192afff8de0SPeter Maydell return true; 193afff8de0SPeter Maydell } 19494d5eb7bSPeter Maydell 19594d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 19694d5eb7bSPeter Maydell { 19794d5eb7bSPeter Maydell int opr_sz; 19894d5eb7bSPeter Maydell TCGv_ptr fpst; 19994d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 20094d5eb7bSPeter Maydell 20194d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 20294d5eb7bSPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 20394d5eb7bSPeter Maydell return false; 20494d5eb7bSPeter Maydell } 20594d5eb7bSPeter Maydell 20694d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 20794d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 20894d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 20994d5eb7bSPeter Maydell return false; 21094d5eb7bSPeter Maydell } 21194d5eb7bSPeter Maydell 21294d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 21394d5eb7bSPeter Maydell return false; 21494d5eb7bSPeter Maydell } 21594d5eb7bSPeter Maydell 21694d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 21794d5eb7bSPeter Maydell return true; 21894d5eb7bSPeter Maydell } 21994d5eb7bSPeter Maydell 22094d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 221b34aa512SPeter Maydell fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD); 22294d5eb7bSPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh; 22394d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 22494d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 22594d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 22694d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 22794d5eb7bSPeter Maydell fn_gvec_ptr); 22894d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 22994d5eb7bSPeter Maydell return true; 23094d5eb7bSPeter Maydell } 23132da0e33SPeter Maydell 23232da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a) 23332da0e33SPeter Maydell { 23432da0e33SPeter Maydell int opr_sz; 23532da0e33SPeter Maydell gen_helper_gvec_3 *fn_gvec; 23632da0e33SPeter Maydell 23732da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 23832da0e33SPeter Maydell return false; 23932da0e33SPeter Maydell } 24032da0e33SPeter Maydell 24132da0e33SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 24232da0e33SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 24332da0e33SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 24432da0e33SPeter Maydell return false; 24532da0e33SPeter Maydell } 24632da0e33SPeter Maydell 24732da0e33SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 24832da0e33SPeter Maydell return false; 24932da0e33SPeter Maydell } 25032da0e33SPeter Maydell 25132da0e33SPeter Maydell if (!vfp_access_check(s)) { 25232da0e33SPeter Maydell return true; 25332da0e33SPeter Maydell } 25432da0e33SPeter Maydell 25532da0e33SPeter Maydell opr_sz = (1 + a->q) * 8; 25632da0e33SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; 25732da0e33SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 25832da0e33SPeter Maydell vfp_reg_offset(1, a->vn), 25932da0e33SPeter Maydell vfp_reg_offset(1, a->vm), 26032da0e33SPeter Maydell opr_sz, opr_sz, 0, fn_gvec); 26132da0e33SPeter Maydell return true; 26232da0e33SPeter Maydell } 2639a107e7bSPeter Maydell 2649a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 2659a107e7bSPeter Maydell { 2669a107e7bSPeter Maydell int opr_sz; 2679a107e7bSPeter Maydell 2689a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 2699a107e7bSPeter Maydell return false; 2709a107e7bSPeter Maydell } 2719a107e7bSPeter Maydell 2729a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2739a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2749a107e7bSPeter Maydell (a->vd & 0x10)) { 2759a107e7bSPeter Maydell return false; 2769a107e7bSPeter Maydell } 2779a107e7bSPeter Maydell 2789a107e7bSPeter Maydell if (a->vd & a->q) { 2799a107e7bSPeter Maydell return false; 2809a107e7bSPeter Maydell } 2819a107e7bSPeter Maydell 2829a107e7bSPeter Maydell if (!vfp_access_check(s)) { 2839a107e7bSPeter Maydell return true; 2849a107e7bSPeter Maydell } 2859a107e7bSPeter Maydell 2869a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 2879a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 2889a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 2899a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 2909a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 2919a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 2929a107e7bSPeter Maydell return true; 2939a107e7bSPeter Maydell } 2947e1b5d61SPeter Maydell 2957e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 2967e1b5d61SPeter Maydell { 2977e1b5d61SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 2987e1b5d61SPeter Maydell int opr_sz; 2997e1b5d61SPeter Maydell TCGv_ptr fpst; 3007e1b5d61SPeter Maydell 3017e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 3027e1b5d61SPeter Maydell return false; 3037e1b5d61SPeter Maydell } 3047e1b5d61SPeter Maydell if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) { 3057e1b5d61SPeter Maydell return false; 3067e1b5d61SPeter Maydell } 3077e1b5d61SPeter Maydell 3087e1b5d61SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3097e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3107e1b5d61SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 3117e1b5d61SPeter Maydell return false; 3127e1b5d61SPeter Maydell } 3137e1b5d61SPeter Maydell 3147e1b5d61SPeter Maydell if ((a->vd | a->vn) & a->q) { 3157e1b5d61SPeter Maydell return false; 3167e1b5d61SPeter Maydell } 3177e1b5d61SPeter Maydell 3187e1b5d61SPeter Maydell if (!vfp_access_check(s)) { 3197e1b5d61SPeter Maydell return true; 3207e1b5d61SPeter Maydell } 3217e1b5d61SPeter Maydell 3227e1b5d61SPeter Maydell fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx 3237e1b5d61SPeter Maydell : gen_helper_gvec_fcmlah_idx); 3247e1b5d61SPeter Maydell opr_sz = (1 + a->q) * 8; 325b34aa512SPeter Maydell fpst = fpstatus_ptr(a->size == 0 ? FPST_STD_F16 : FPST_STD); 3267e1b5d61SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 3277e1b5d61SPeter Maydell vfp_reg_offset(1, a->vn), 3287e1b5d61SPeter Maydell vfp_reg_offset(1, a->vm), 3297e1b5d61SPeter Maydell fpst, opr_sz, opr_sz, 3307e1b5d61SPeter Maydell (a->index << 2) | a->rot, fn_gvec_ptr); 3317e1b5d61SPeter Maydell tcg_temp_free_ptr(fpst); 3327e1b5d61SPeter Maydell return true; 3337e1b5d61SPeter Maydell } 33435f5d4d1SPeter Maydell 33535f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) 33635f5d4d1SPeter Maydell { 33735f5d4d1SPeter Maydell gen_helper_gvec_3 *fn_gvec; 33835f5d4d1SPeter Maydell int opr_sz; 33935f5d4d1SPeter Maydell TCGv_ptr fpst; 34035f5d4d1SPeter Maydell 34135f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 34235f5d4d1SPeter Maydell return false; 34335f5d4d1SPeter Maydell } 34435f5d4d1SPeter Maydell 34535f5d4d1SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 34635f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 34735f5d4d1SPeter Maydell ((a->vd | a->vn) & 0x10)) { 34835f5d4d1SPeter Maydell return false; 34935f5d4d1SPeter Maydell } 35035f5d4d1SPeter Maydell 35135f5d4d1SPeter Maydell if ((a->vd | a->vn) & a->q) { 35235f5d4d1SPeter Maydell return false; 35335f5d4d1SPeter Maydell } 35435f5d4d1SPeter Maydell 35535f5d4d1SPeter Maydell if (!vfp_access_check(s)) { 35635f5d4d1SPeter Maydell return true; 35735f5d4d1SPeter Maydell } 35835f5d4d1SPeter Maydell 35935f5d4d1SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; 36035f5d4d1SPeter Maydell opr_sz = (1 + a->q) * 8; 361a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 36235f5d4d1SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 36335f5d4d1SPeter Maydell vfp_reg_offset(1, a->vn), 36435f5d4d1SPeter Maydell vfp_reg_offset(1, a->rm), 36535f5d4d1SPeter Maydell opr_sz, opr_sz, a->index, fn_gvec); 36635f5d4d1SPeter Maydell tcg_temp_free_ptr(fpst); 36735f5d4d1SPeter Maydell return true; 36835f5d4d1SPeter Maydell } 369d27e82f7SPeter Maydell 370d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 371d27e82f7SPeter Maydell { 372d27e82f7SPeter Maydell int opr_sz; 373d27e82f7SPeter Maydell 374d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 375d27e82f7SPeter Maydell return false; 376d27e82f7SPeter Maydell } 377d27e82f7SPeter Maydell 378d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 379d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 380d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 381d27e82f7SPeter Maydell return false; 382d27e82f7SPeter Maydell } 383d27e82f7SPeter Maydell 384d27e82f7SPeter Maydell if (a->vd & a->q) { 385d27e82f7SPeter Maydell return false; 386d27e82f7SPeter Maydell } 387d27e82f7SPeter Maydell 388d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 389d27e82f7SPeter Maydell return true; 390d27e82f7SPeter Maydell } 391d27e82f7SPeter Maydell 392d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 393d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 394d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 395d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 396d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 397d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 398d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 399d27e82f7SPeter Maydell return true; 400d27e82f7SPeter Maydell } 401a27b4630SPeter Maydell 402a27b4630SPeter Maydell static struct { 403a27b4630SPeter Maydell int nregs; 404a27b4630SPeter Maydell int interleave; 405a27b4630SPeter Maydell int spacing; 406a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 407a27b4630SPeter Maydell {1, 4, 1}, 408a27b4630SPeter Maydell {1, 4, 2}, 409a27b4630SPeter Maydell {4, 1, 1}, 410a27b4630SPeter Maydell {2, 2, 2}, 411a27b4630SPeter Maydell {1, 3, 1}, 412a27b4630SPeter Maydell {1, 3, 2}, 413a27b4630SPeter Maydell {3, 1, 1}, 414a27b4630SPeter Maydell {1, 1, 1}, 415a27b4630SPeter Maydell {1, 2, 1}, 416a27b4630SPeter Maydell {1, 2, 2}, 417a27b4630SPeter Maydell {2, 1, 1} 418a27b4630SPeter Maydell }; 419a27b4630SPeter Maydell 420a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 421a27b4630SPeter Maydell int stride) 422a27b4630SPeter Maydell { 423a27b4630SPeter Maydell if (rm != 15) { 424a27b4630SPeter Maydell TCGv_i32 base; 425a27b4630SPeter Maydell 426a27b4630SPeter Maydell base = load_reg(s, rn); 427a27b4630SPeter Maydell if (rm == 13) { 428a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 429a27b4630SPeter Maydell } else { 430a27b4630SPeter Maydell TCGv_i32 index; 431a27b4630SPeter Maydell index = load_reg(s, rm); 432a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 433a27b4630SPeter Maydell tcg_temp_free_i32(index); 434a27b4630SPeter Maydell } 435a27b4630SPeter Maydell store_reg(s, rn, base); 436a27b4630SPeter Maydell } 437a27b4630SPeter Maydell } 438a27b4630SPeter Maydell 439a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 440a27b4630SPeter Maydell { 441a27b4630SPeter Maydell /* Neon load/store multiple structures */ 442a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 443a27b4630SPeter Maydell MemOp endian = s->be_data; 444a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 445a27b4630SPeter Maydell int size = a->size; 446a27b4630SPeter Maydell TCGv_i64 tmp64; 447a27b4630SPeter Maydell TCGv_i32 addr, tmp; 448a27b4630SPeter Maydell 449a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 450a27b4630SPeter Maydell return false; 451a27b4630SPeter Maydell } 452a27b4630SPeter Maydell 453a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 454a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 455a27b4630SPeter Maydell return false; 456a27b4630SPeter Maydell } 457a27b4630SPeter Maydell if (a->itype > 10) { 458a27b4630SPeter Maydell return false; 459a27b4630SPeter Maydell } 460a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 461a27b4630SPeter Maydell switch (a->itype & 0xc) { 462a27b4630SPeter Maydell case 4: 463a27b4630SPeter Maydell if (a->align >= 2) { 464a27b4630SPeter Maydell return false; 465a27b4630SPeter Maydell } 466a27b4630SPeter Maydell break; 467a27b4630SPeter Maydell case 8: 468a27b4630SPeter Maydell if (a->align == 3) { 469a27b4630SPeter Maydell return false; 470a27b4630SPeter Maydell } 471a27b4630SPeter Maydell break; 472a27b4630SPeter Maydell default: 473a27b4630SPeter Maydell break; 474a27b4630SPeter Maydell } 475a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 476a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 477a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 478a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 479a27b4630SPeter Maydell return false; 480a27b4630SPeter Maydell } 481a27b4630SPeter Maydell 482a27b4630SPeter Maydell if (!vfp_access_check(s)) { 483a27b4630SPeter Maydell return true; 484a27b4630SPeter Maydell } 485a27b4630SPeter Maydell 486a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 487a27b4630SPeter Maydell if (size == 0) { 488a27b4630SPeter Maydell endian = MO_LE; 489a27b4630SPeter Maydell } 490a27b4630SPeter Maydell /* 491a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 492a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 493a27b4630SPeter Maydell */ 494a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 495a27b4630SPeter Maydell size = 3; 496a27b4630SPeter Maydell } 497a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 498a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 499a27b4630SPeter Maydell tmp = tcg_const_i32(1 << size); 500a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 501a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 502a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 503a27b4630SPeter Maydell int xs; 504a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 505a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 506a27b4630SPeter Maydell 507a27b4630SPeter Maydell if (a->l) { 508a27b4630SPeter Maydell gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); 509a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 510a27b4630SPeter Maydell } else { 511a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 512a27b4630SPeter Maydell gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); 513a27b4630SPeter Maydell } 514a27b4630SPeter Maydell tcg_gen_add_i32(addr, addr, tmp); 515a27b4630SPeter Maydell } 516a27b4630SPeter Maydell } 517a27b4630SPeter Maydell } 518a27b4630SPeter Maydell tcg_temp_free_i32(addr); 519a27b4630SPeter Maydell tcg_temp_free_i32(tmp); 520a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 521a27b4630SPeter Maydell 522a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 523a27b4630SPeter Maydell return true; 524a27b4630SPeter Maydell } 5253698747cSPeter Maydell 5263698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5273698747cSPeter Maydell { 5283698747cSPeter Maydell /* Neon load single structure to all lanes */ 5293698747cSPeter Maydell int reg, stride, vec_size; 5303698747cSPeter Maydell int vd = a->vd; 5313698747cSPeter Maydell int size = a->size; 5323698747cSPeter Maydell int nregs = a->n + 1; 5333698747cSPeter Maydell TCGv_i32 addr, tmp; 5343698747cSPeter Maydell 5353698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5363698747cSPeter Maydell return false; 5373698747cSPeter Maydell } 5383698747cSPeter Maydell 5393698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5403698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5413698747cSPeter Maydell return false; 5423698747cSPeter Maydell } 5433698747cSPeter Maydell 5443698747cSPeter Maydell if (size == 3) { 5453698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5463698747cSPeter Maydell return false; 5473698747cSPeter Maydell } 5483698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 5493698747cSPeter Maydell size = 2; 5503698747cSPeter Maydell } 5513698747cSPeter Maydell if (nregs == 1 && a->a == 1 && size == 0) { 5523698747cSPeter Maydell return false; 5533698747cSPeter Maydell } 5543698747cSPeter Maydell if (nregs == 3 && a->a == 1) { 5553698747cSPeter Maydell return false; 5563698747cSPeter Maydell } 5573698747cSPeter Maydell 5583698747cSPeter Maydell if (!vfp_access_check(s)) { 5593698747cSPeter Maydell return true; 5603698747cSPeter Maydell } 5613698747cSPeter Maydell 5623698747cSPeter Maydell /* 5633698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 5643698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 5653698747cSPeter Maydell */ 5663698747cSPeter Maydell stride = a->t ? 2 : 1; 5673698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 5683698747cSPeter Maydell 5693698747cSPeter Maydell tmp = tcg_temp_new_i32(); 5703698747cSPeter Maydell addr = tcg_temp_new_i32(); 5713698747cSPeter Maydell load_reg_var(s, addr, a->rn); 5723698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 5733698747cSPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 5743698747cSPeter Maydell s->be_data | size); 5753698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 5763698747cSPeter Maydell /* 5773698747cSPeter Maydell * We cannot write 16 bytes at once because the 5783698747cSPeter Maydell * destination is unaligned. 5793698747cSPeter Maydell */ 5803698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 5813698747cSPeter Maydell 8, 8, tmp); 5823698747cSPeter Maydell tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0), 5833698747cSPeter Maydell neon_reg_offset(vd, 0), 8, 8); 5843698747cSPeter Maydell } else { 5853698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 5863698747cSPeter Maydell vec_size, vec_size, tmp); 5873698747cSPeter Maydell } 5883698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 5893698747cSPeter Maydell vd += stride; 5903698747cSPeter Maydell } 5913698747cSPeter Maydell tcg_temp_free_i32(tmp); 5923698747cSPeter Maydell tcg_temp_free_i32(addr); 5933698747cSPeter Maydell 5943698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 5953698747cSPeter Maydell 5963698747cSPeter Maydell return true; 5973698747cSPeter Maydell } 598123ce4e3SPeter Maydell 599123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 600123ce4e3SPeter Maydell { 601123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 602123ce4e3SPeter Maydell int reg; 603123ce4e3SPeter Maydell int nregs = a->n + 1; 604123ce4e3SPeter Maydell int vd = a->vd; 605123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 606123ce4e3SPeter Maydell 607123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 608123ce4e3SPeter Maydell return false; 609123ce4e3SPeter Maydell } 610123ce4e3SPeter Maydell 611123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 612123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 613123ce4e3SPeter Maydell return false; 614123ce4e3SPeter Maydell } 615123ce4e3SPeter Maydell 616123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 617123ce4e3SPeter Maydell switch (nregs) { 618123ce4e3SPeter Maydell case 1: 619123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 620123ce4e3SPeter Maydell (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) { 621123ce4e3SPeter Maydell return false; 622123ce4e3SPeter Maydell } 623123ce4e3SPeter Maydell break; 624123ce4e3SPeter Maydell case 3: 625123ce4e3SPeter Maydell if ((a->align & 1) != 0) { 626123ce4e3SPeter Maydell return false; 627123ce4e3SPeter Maydell } 628123ce4e3SPeter Maydell /* fall through */ 629123ce4e3SPeter Maydell case 2: 630123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 631123ce4e3SPeter Maydell return false; 632123ce4e3SPeter Maydell } 633123ce4e3SPeter Maydell break; 634123ce4e3SPeter Maydell case 4: 635123ce4e3SPeter Maydell if ((a->size == 2) && ((a->align & 3) == 3)) { 636123ce4e3SPeter Maydell return false; 637123ce4e3SPeter Maydell } 638123ce4e3SPeter Maydell break; 639123ce4e3SPeter Maydell default: 640123ce4e3SPeter Maydell abort(); 641123ce4e3SPeter Maydell } 642123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 643123ce4e3SPeter Maydell /* 644123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 645123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 646123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 647123ce4e3SPeter Maydell */ 648123ce4e3SPeter Maydell return false; 649123ce4e3SPeter Maydell } 650123ce4e3SPeter Maydell 651123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 652123ce4e3SPeter Maydell return true; 653123ce4e3SPeter Maydell } 654123ce4e3SPeter Maydell 655123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 656123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 657123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 658123ce4e3SPeter Maydell /* 659123ce4e3SPeter Maydell * TODO: if we implemented alignment exceptions, we should check 660123ce4e3SPeter Maydell * addr against the alignment encoded in a->align here. 661123ce4e3SPeter Maydell */ 662123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 663123ce4e3SPeter Maydell if (a->l) { 664123ce4e3SPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 665123ce4e3SPeter Maydell s->be_data | a->size); 666123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 667123ce4e3SPeter Maydell } else { /* Store */ 668123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 669123ce4e3SPeter Maydell gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), 670123ce4e3SPeter Maydell s->be_data | a->size); 671123ce4e3SPeter Maydell } 672123ce4e3SPeter Maydell vd += a->stride; 673123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 674123ce4e3SPeter Maydell } 675123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 676123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 677123ce4e3SPeter Maydell 678123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 679123ce4e3SPeter Maydell 680123ce4e3SPeter Maydell return true; 681123ce4e3SPeter Maydell } 682a4e143acSPeter Maydell 683a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 684a4e143acSPeter Maydell { 685a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 686a4e143acSPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 687a4e143acSPeter Maydell int rn_ofs = neon_reg_offset(a->vn, 0); 688a4e143acSPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 689a4e143acSPeter Maydell 690a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 691a4e143acSPeter Maydell return false; 692a4e143acSPeter Maydell } 693a4e143acSPeter Maydell 694a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 695a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 696a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 697a4e143acSPeter Maydell return false; 698a4e143acSPeter Maydell } 699a4e143acSPeter Maydell 700a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 701a4e143acSPeter Maydell return false; 702a4e143acSPeter Maydell } 703a4e143acSPeter Maydell 704a4e143acSPeter Maydell if (!vfp_access_check(s)) { 705a4e143acSPeter Maydell return true; 706a4e143acSPeter Maydell } 707a4e143acSPeter Maydell 708a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 709a4e143acSPeter Maydell return true; 710a4e143acSPeter Maydell } 711a4e143acSPeter Maydell 712a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 713a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 714a4e143acSPeter Maydell { \ 715a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 716a4e143acSPeter Maydell } 717a4e143acSPeter Maydell 718a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 719a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 72035a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 72135a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 72235a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 72335a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 72435a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 7258161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 7268161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 727c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 728c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 729c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 730c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 73135a548edSPeter Maydell 73235a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 73335a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 73435a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 73535a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 73635a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 73735a548edSPeter Maydell { \ 73835a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 73935a548edSPeter Maydell } \ 74035a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 74135a548edSPeter Maydell 74235a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 74335a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 74435a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 74536b59310SPeter Maydell 74636b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 74736b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 74836b59310SPeter Maydell { \ 74936b59310SPeter Maydell if (a->size == 3) { \ 75036b59310SPeter Maydell return false; \ 75136b59310SPeter Maydell } \ 75236b59310SPeter Maydell return do_3same(s, a, FUNC); \ 75336b59310SPeter Maydell } 75436b59310SPeter Maydell 75536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 75636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 75736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 75836b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 7590de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 76027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 76127106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 7628161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 7637715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 7647715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 7657715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 7667715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 76702bd0cdbSPeter Maydell 76802bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 76902bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 77002bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 77102bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 77202bd0cdbSPeter Maydell { \ 77302bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 77402bd0cdbSPeter Maydell } \ 77502bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 77602bd0cdbSPeter Maydell 77702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 77802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 77902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 78002bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 78102bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 78202bd0cdbSPeter Maydell 783effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 784effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 785effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 786effa992fSRichard Henderson { \ 787effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 7880de34fd4SPeter Maydell } 7890de34fd4SPeter Maydell 790effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 791effa992fSRichard Henderson 7920de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 7930de34fd4SPeter Maydell { 7940de34fd4SPeter Maydell if (a->size != 0) { 7950de34fd4SPeter Maydell return false; 7960de34fd4SPeter Maydell } 7970de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 7980de34fd4SPeter Maydell } 799a0635695SPeter Maydell 800a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 801a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 802a0635695SPeter Maydell { \ 803a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 804a0635695SPeter Maydell return false; \ 805a0635695SPeter Maydell } \ 806a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 807a0635695SPeter Maydell return false; \ 808a0635695SPeter Maydell } \ 809a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 810a0635695SPeter Maydell } 811a0635695SPeter Maydell 812a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 813a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 81421290edfSPeter Maydell 815afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 816afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 817afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 818afc8b7d3SRichard Henderson { \ 819afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 820afc8b7d3SRichard Henderson return false; \ 821afc8b7d3SRichard Henderson } \ 822afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 82321290edfSPeter Maydell } 82421290edfSPeter Maydell 825afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 826afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 827afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 828afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 82921290edfSPeter Maydell 830effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 831effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 832effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 833effa992fSRichard Henderson { \ 834effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 835effa992fSRichard Henderson return false; \ 836effa992fSRichard Henderson } \ 837effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 83821290edfSPeter Maydell } 83921290edfSPeter Maydell 840effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 841effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 842effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 84335d4352fSPeter Maydell 84435d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 84535d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 84635d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 84735d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 84835d4352fSPeter Maydell { \ 84935d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 85035d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 85135d4352fSPeter Maydell } \ 85235d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 85335d4352fSPeter Maydell 85435d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 85535d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 85635d4352fSPeter Maydell { \ 85735d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 85835d4352fSPeter Maydell } \ 85935d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 86035d4352fSPeter Maydell 86135d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 86235d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 86335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 86435d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 86535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 86635d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 867cb294bcaSPeter Maydell 868cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 869cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 870cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 871cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 872cb294bcaSPeter Maydell { \ 873cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 874cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 875cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 876cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 877cb294bcaSPeter Maydell { 0 }, \ 878cb294bcaSPeter Maydell }; \ 879cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 880cb294bcaSPeter Maydell } \ 881cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 882cb294bcaSPeter Maydell { \ 883cb294bcaSPeter Maydell if (a->size > 2) { \ 884cb294bcaSPeter Maydell return false; \ 885cb294bcaSPeter Maydell } \ 886cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 887cb294bcaSPeter Maydell } 888cb294bcaSPeter Maydell 8896812dfdcSPeter Maydell /* 8906812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 8916812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 8926812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 8936812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 8946812dfdcSPeter Maydell */ 8956812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 8966812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 8976812dfdcSPeter Maydell { \ 8986812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 8996812dfdcSPeter Maydell } 9006812dfdcSPeter Maydell 9016812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 9026812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 9036812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 9046812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 9056812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9066812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9076812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9086812dfdcSPeter Maydell { \ 9096812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 9106812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9116812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9126812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9136812dfdcSPeter Maydell { 0 }, \ 9146812dfdcSPeter Maydell }; \ 9156812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 9166812dfdcSPeter Maydell } \ 9176812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9186812dfdcSPeter Maydell { \ 9196812dfdcSPeter Maydell if (a->size > 2) { \ 9206812dfdcSPeter Maydell return false; \ 9216812dfdcSPeter Maydell } \ 9226812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 9236812dfdcSPeter Maydell } 9246812dfdcSPeter Maydell 925cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 926cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 9278e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 9288e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 9298e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 9308e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 9316812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 9326812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 9336812dfdcSPeter Maydell 9346812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 9356812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 9366812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 9376812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 938059c2398SPeter Maydell 939059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 940059c2398SPeter Maydell { 941059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 942059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 943059c2398SPeter Maydell 944059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 945059c2398SPeter Maydell return false; 946059c2398SPeter Maydell } 947059c2398SPeter Maydell 948059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 949059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 950059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 951059c2398SPeter Maydell return false; 952059c2398SPeter Maydell } 953059c2398SPeter Maydell 954059c2398SPeter Maydell if (a->size == 3) { 955059c2398SPeter Maydell return false; 956059c2398SPeter Maydell } 957059c2398SPeter Maydell 958059c2398SPeter Maydell if (!vfp_access_check(s)) { 959059c2398SPeter Maydell return true; 960059c2398SPeter Maydell } 961059c2398SPeter Maydell 962059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 963059c2398SPeter Maydell 964059c2398SPeter Maydell /* 965059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 966059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 967059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 968059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 969059c2398SPeter Maydell */ 970059c2398SPeter Maydell tmp = neon_load_reg(a->vn, 0); 971059c2398SPeter Maydell tmp2 = neon_load_reg(a->vn, 1); 972059c2398SPeter Maydell fn(tmp, tmp, tmp2); 973059c2398SPeter Maydell tcg_temp_free_i32(tmp2); 974059c2398SPeter Maydell 975059c2398SPeter Maydell tmp3 = neon_load_reg(a->vm, 0); 976059c2398SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 977059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 978059c2398SPeter Maydell tcg_temp_free_i32(tmp2); 979059c2398SPeter Maydell 980059c2398SPeter Maydell neon_store_reg(a->vd, 0, tmp); 981059c2398SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 982059c2398SPeter Maydell return true; 983059c2398SPeter Maydell } 984059c2398SPeter Maydell 985059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 986059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 987059c2398SPeter Maydell { \ 988059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 989059c2398SPeter Maydell gen_helper_neon_##func##8, \ 990059c2398SPeter Maydell gen_helper_neon_##func##16, \ 991059c2398SPeter Maydell gen_helper_neon_##func##32, \ 992059c2398SPeter Maydell }; \ 993059c2398SPeter Maydell if (a->size > 2) { \ 994059c2398SPeter Maydell return false; \ 995059c2398SPeter Maydell } \ 996059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 997059c2398SPeter Maydell } 998059c2398SPeter Maydell 999059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 1000059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 1001059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 1002059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 1003059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 1004fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1005059c2398SPeter Maydell 1006059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1007059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1008059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1009059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1010fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 10117ecc28bcSPeter Maydell 10127ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 10137ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 10147ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 10157ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 10167ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 10177ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 10187ecc28bcSPeter Maydell { \ 10197ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 10207ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 10217ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 10227ecc28bcSPeter Maydell }; \ 10237ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 10247ecc28bcSPeter Maydell } \ 10257ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 10267ecc28bcSPeter Maydell { \ 10277ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 10287ecc28bcSPeter Maydell return false; \ 10297ecc28bcSPeter Maydell } \ 10307ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 10317ecc28bcSPeter Maydell } 10327ecc28bcSPeter Maydell 10337ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 10347ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1035a26a352bSPeter Maydell 10368aa71eadSPeter Maydell static bool do_3same_fp(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn, 10378aa71eadSPeter Maydell bool reads_vd) 10388aa71eadSPeter Maydell { 10398aa71eadSPeter Maydell /* 10408aa71eadSPeter Maydell * FP operations handled elementwise 32 bits at a time. 10418aa71eadSPeter Maydell * If reads_vd is true then the old value of Vd will be 10428aa71eadSPeter Maydell * loaded before calling the callback function. This is 10438aa71eadSPeter Maydell * used for multiply-accumulate type operations. 10448aa71eadSPeter Maydell */ 10458aa71eadSPeter Maydell TCGv_i32 tmp, tmp2; 10468aa71eadSPeter Maydell int pass; 10478aa71eadSPeter Maydell 10488aa71eadSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 10498aa71eadSPeter Maydell return false; 10508aa71eadSPeter Maydell } 10518aa71eadSPeter Maydell 10528aa71eadSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 10538aa71eadSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 10548aa71eadSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 10558aa71eadSPeter Maydell return false; 10568aa71eadSPeter Maydell } 10578aa71eadSPeter Maydell 10588aa71eadSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 10598aa71eadSPeter Maydell return false; 10608aa71eadSPeter Maydell } 10618aa71eadSPeter Maydell 10628aa71eadSPeter Maydell if (!vfp_access_check(s)) { 10638aa71eadSPeter Maydell return true; 10648aa71eadSPeter Maydell } 10658aa71eadSPeter Maydell 1066a84d1d13SPeter Maydell TCGv_ptr fpstatus = fpstatus_ptr(FPST_STD); 10678aa71eadSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 10688aa71eadSPeter Maydell tmp = neon_load_reg(a->vn, pass); 10698aa71eadSPeter Maydell tmp2 = neon_load_reg(a->vm, pass); 10708aa71eadSPeter Maydell if (reads_vd) { 10718aa71eadSPeter Maydell TCGv_i32 tmp_rd = neon_load_reg(a->vd, pass); 10728aa71eadSPeter Maydell fn(tmp_rd, tmp, tmp2, fpstatus); 10738aa71eadSPeter Maydell neon_store_reg(a->vd, pass, tmp_rd); 10748aa71eadSPeter Maydell tcg_temp_free_i32(tmp); 10758aa71eadSPeter Maydell } else { 10768aa71eadSPeter Maydell fn(tmp, tmp, tmp2, fpstatus); 10778aa71eadSPeter Maydell neon_store_reg(a->vd, pass, tmp); 10788aa71eadSPeter Maydell } 10798aa71eadSPeter Maydell tcg_temp_free_i32(tmp2); 10808aa71eadSPeter Maydell } 10818aa71eadSPeter Maydell tcg_temp_free_ptr(fpstatus); 10828aa71eadSPeter Maydell return true; 10838aa71eadSPeter Maydell } 10848aa71eadSPeter Maydell 1085*e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1086*e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1087a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1088a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1089a26a352bSPeter Maydell { \ 1090*e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1091a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1092a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1093a26a352bSPeter Maydell tcg_temp_free_ptr(fpst); \ 1094*e4a6d4a6SPeter Maydell } 1095*e4a6d4a6SPeter Maydell 1096*e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1097*e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1098*e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1099a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1100a26a352bSPeter Maydell { \ 1101a26a352bSPeter Maydell if (a->size != 0) { \ 1102*e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1103a26a352bSPeter Maydell return false; \ 1104a26a352bSPeter Maydell } \ 1105*e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1106*e4a6d4a6SPeter Maydell } \ 1107*e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1108a26a352bSPeter Maydell } 1109a26a352bSPeter Maydell 1110a26a352bSPeter Maydell 1111*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1112*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1113*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1114*e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 11158aa71eadSPeter Maydell 11168aa71eadSPeter Maydell /* 11178aa71eadSPeter Maydell * For all the functions using this macro, size == 1 means fp16, 11188aa71eadSPeter Maydell * which is an architecture extension we don't implement yet. 11198aa71eadSPeter Maydell */ 11208aa71eadSPeter Maydell #define DO_3S_FP(INSN,FUNC,READS_VD) \ 11218aa71eadSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 11228aa71eadSPeter Maydell { \ 11238aa71eadSPeter Maydell if (a->size != 0) { \ 11248aa71eadSPeter Maydell /* TODO fp16 support */ \ 11258aa71eadSPeter Maydell return false; \ 11268aa71eadSPeter Maydell } \ 11278aa71eadSPeter Maydell return do_3same_fp(s, a, FUNC, READS_VD); \ 11288aa71eadSPeter Maydell } 11298aa71eadSPeter Maydell 1130727ff1d6SPeter Maydell DO_3S_FP(VCEQ, gen_helper_neon_ceq_f32, false) 1131727ff1d6SPeter Maydell DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false) 1132727ff1d6SPeter Maydell DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false) 1133727ff1d6SPeter Maydell DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false) 1134727ff1d6SPeter Maydell DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false) 1135d5fdf9e9SPeter Maydell DO_3S_FP(VMAX, gen_helper_vfp_maxs, false) 1136d5fdf9e9SPeter Maydell DO_3S_FP(VMIN, gen_helper_vfp_mins, false) 1137727ff1d6SPeter Maydell 11388aa71eadSPeter Maydell static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 11398aa71eadSPeter Maydell TCGv_ptr fpstatus) 11408aa71eadSPeter Maydell { 11418aa71eadSPeter Maydell gen_helper_vfp_muls(vn, vn, vm, fpstatus); 11428aa71eadSPeter Maydell gen_helper_vfp_adds(vd, vd, vn, fpstatus); 11438aa71eadSPeter Maydell } 11448aa71eadSPeter Maydell 11458aa71eadSPeter Maydell static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 11468aa71eadSPeter Maydell TCGv_ptr fpstatus) 11478aa71eadSPeter Maydell { 11488aa71eadSPeter Maydell gen_helper_vfp_muls(vn, vn, vm, fpstatus); 11498aa71eadSPeter Maydell gen_helper_vfp_subs(vd, vd, vn, fpstatus); 11508aa71eadSPeter Maydell } 11518aa71eadSPeter Maydell 11528aa71eadSPeter Maydell DO_3S_FP(VMLA, gen_VMLA_fp_3s, true) 11538aa71eadSPeter Maydell DO_3S_FP(VMLS, gen_VMLS_fp_3s, true) 1154ab978335SPeter Maydell 1155d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1156d5fdf9e9SPeter Maydell { 1157d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1158d5fdf9e9SPeter Maydell return false; 1159d5fdf9e9SPeter Maydell } 1160d5fdf9e9SPeter Maydell 1161d5fdf9e9SPeter Maydell if (a->size != 0) { 1162d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1163d5fdf9e9SPeter Maydell return false; 1164d5fdf9e9SPeter Maydell } 1165d5fdf9e9SPeter Maydell 1166d5fdf9e9SPeter Maydell return do_3same_fp(s, a, gen_helper_vfp_maxnums, false); 1167d5fdf9e9SPeter Maydell } 1168d5fdf9e9SPeter Maydell 1169d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1170d5fdf9e9SPeter Maydell { 1171d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1172d5fdf9e9SPeter Maydell return false; 1173d5fdf9e9SPeter Maydell } 1174d5fdf9e9SPeter Maydell 1175d5fdf9e9SPeter Maydell if (a->size != 0) { 1176d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1177d5fdf9e9SPeter Maydell return false; 1178d5fdf9e9SPeter Maydell } 1179d5fdf9e9SPeter Maydell 1180d5fdf9e9SPeter Maydell return do_3same_fp(s, a, gen_helper_vfp_minnums, false); 1181d5fdf9e9SPeter Maydell } 1182d5fdf9e9SPeter Maydell 1183d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRECPS_tramp, gen_helper_recps_f32) 1184d5fdf9e9SPeter Maydell 1185d5fdf9e9SPeter Maydell static void gen_VRECPS_fp_3s(unsigned vece, uint32_t rd_ofs, 1186d5fdf9e9SPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, 1187d5fdf9e9SPeter Maydell uint32_t oprsz, uint32_t maxsz) 1188d5fdf9e9SPeter Maydell { 1189d5fdf9e9SPeter Maydell static const GVecGen3 ops = { .fni4 = gen_VRECPS_tramp }; 1190d5fdf9e9SPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); 1191d5fdf9e9SPeter Maydell } 1192d5fdf9e9SPeter Maydell 1193d5fdf9e9SPeter Maydell static bool trans_VRECPS_fp_3s(DisasContext *s, arg_3same *a) 1194d5fdf9e9SPeter Maydell { 1195d5fdf9e9SPeter Maydell if (a->size != 0) { 1196d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1197d5fdf9e9SPeter Maydell return false; 1198d5fdf9e9SPeter Maydell } 1199d5fdf9e9SPeter Maydell 1200d5fdf9e9SPeter Maydell return do_3same(s, a, gen_VRECPS_fp_3s); 1201d5fdf9e9SPeter Maydell } 1202d5fdf9e9SPeter Maydell 1203d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRSQRTS_tramp, gen_helper_rsqrts_f32) 1204d5fdf9e9SPeter Maydell 1205d5fdf9e9SPeter Maydell static void gen_VRSQRTS_fp_3s(unsigned vece, uint32_t rd_ofs, 1206d5fdf9e9SPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, 1207d5fdf9e9SPeter Maydell uint32_t oprsz, uint32_t maxsz) 1208d5fdf9e9SPeter Maydell { 1209d5fdf9e9SPeter Maydell static const GVecGen3 ops = { .fni4 = gen_VRSQRTS_tramp }; 1210d5fdf9e9SPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); 1211d5fdf9e9SPeter Maydell } 1212d5fdf9e9SPeter Maydell 1213d5fdf9e9SPeter Maydell static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a) 1214d5fdf9e9SPeter Maydell { 1215d5fdf9e9SPeter Maydell if (a->size != 0) { 1216d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1217d5fdf9e9SPeter Maydell return false; 1218d5fdf9e9SPeter Maydell } 1219d5fdf9e9SPeter Maydell 1220d5fdf9e9SPeter Maydell return do_3same(s, a, gen_VRSQRTS_fp_3s); 1221d5fdf9e9SPeter Maydell } 1222d5fdf9e9SPeter Maydell 1223e95485f8SPeter Maydell static void gen_VFMA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 1224e95485f8SPeter Maydell TCGv_ptr fpstatus) 1225e95485f8SPeter Maydell { 1226e95485f8SPeter Maydell gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); 1227e95485f8SPeter Maydell } 1228e95485f8SPeter Maydell 1229e95485f8SPeter Maydell static bool trans_VFMA_fp_3s(DisasContext *s, arg_3same *a) 1230e95485f8SPeter Maydell { 1231e95485f8SPeter Maydell if (!dc_isar_feature(aa32_simdfmac, s)) { 1232e95485f8SPeter Maydell return false; 1233e95485f8SPeter Maydell } 1234e95485f8SPeter Maydell 1235e95485f8SPeter Maydell if (a->size != 0) { 1236e95485f8SPeter Maydell /* TODO fp16 support */ 1237e95485f8SPeter Maydell return false; 1238e95485f8SPeter Maydell } 1239e95485f8SPeter Maydell 1240e95485f8SPeter Maydell return do_3same_fp(s, a, gen_VFMA_fp_3s, true); 1241e95485f8SPeter Maydell } 1242e95485f8SPeter Maydell 1243e95485f8SPeter Maydell static void gen_VFMS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 1244e95485f8SPeter Maydell TCGv_ptr fpstatus) 1245e95485f8SPeter Maydell { 1246e95485f8SPeter Maydell gen_helper_vfp_negs(vn, vn); 1247e95485f8SPeter Maydell gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); 1248e95485f8SPeter Maydell } 1249e95485f8SPeter Maydell 1250e95485f8SPeter Maydell static bool trans_VFMS_fp_3s(DisasContext *s, arg_3same *a) 1251e95485f8SPeter Maydell { 1252e95485f8SPeter Maydell if (!dc_isar_feature(aa32_simdfmac, s)) { 1253e95485f8SPeter Maydell return false; 1254e95485f8SPeter Maydell } 1255e95485f8SPeter Maydell 1256e95485f8SPeter Maydell if (a->size != 0) { 1257e95485f8SPeter Maydell /* TODO fp16 support */ 1258e95485f8SPeter Maydell return false; 1259e95485f8SPeter Maydell } 1260e95485f8SPeter Maydell 1261e95485f8SPeter Maydell return do_3same_fp(s, a, gen_VFMS_fp_3s, true); 1262e95485f8SPeter Maydell } 1263e95485f8SPeter Maydell 1264ab978335SPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) 1265ab978335SPeter Maydell { 1266ab978335SPeter Maydell /* FP operations handled pairwise 32 bits at a time */ 1267ab978335SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1268ab978335SPeter Maydell TCGv_ptr fpstatus; 1269ab978335SPeter Maydell 1270ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1271ab978335SPeter Maydell return false; 1272ab978335SPeter Maydell } 1273ab978335SPeter Maydell 1274ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1275ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1276ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1277ab978335SPeter Maydell return false; 1278ab978335SPeter Maydell } 1279ab978335SPeter Maydell 1280ab978335SPeter Maydell if (!vfp_access_check(s)) { 1281ab978335SPeter Maydell return true; 1282ab978335SPeter Maydell } 1283ab978335SPeter Maydell 1284ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1285ab978335SPeter Maydell 1286ab978335SPeter Maydell /* 1287ab978335SPeter Maydell * Note that we have to be careful not to clobber the source operands 1288ab978335SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1289ab978335SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1290ab978335SPeter Maydell * of a complicated loop over each pass we just unroll. 1291ab978335SPeter Maydell */ 1292a84d1d13SPeter Maydell fpstatus = fpstatus_ptr(FPST_STD); 1293ab978335SPeter Maydell tmp = neon_load_reg(a->vn, 0); 1294ab978335SPeter Maydell tmp2 = neon_load_reg(a->vn, 1); 1295ab978335SPeter Maydell fn(tmp, tmp, tmp2, fpstatus); 1296ab978335SPeter Maydell tcg_temp_free_i32(tmp2); 1297ab978335SPeter Maydell 1298ab978335SPeter Maydell tmp3 = neon_load_reg(a->vm, 0); 1299ab978335SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 1300ab978335SPeter Maydell fn(tmp3, tmp3, tmp2, fpstatus); 1301ab978335SPeter Maydell tcg_temp_free_i32(tmp2); 1302ab978335SPeter Maydell tcg_temp_free_ptr(fpstatus); 1303ab978335SPeter Maydell 1304ab978335SPeter Maydell neon_store_reg(a->vd, 0, tmp); 1305ab978335SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 1306ab978335SPeter Maydell return true; 1307ab978335SPeter Maydell } 1308ab978335SPeter Maydell 1309ab978335SPeter Maydell /* 1310ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1311ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1312ab978335SPeter Maydell */ 1313ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1314ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1315ab978335SPeter Maydell { \ 1316ab978335SPeter Maydell if (a->size != 0) { \ 1317ab978335SPeter Maydell /* TODO fp16 support */ \ 1318ab978335SPeter Maydell return false; \ 1319ab978335SPeter Maydell } \ 1320ab978335SPeter Maydell return do_3same_fp_pair(s, a, FUNC); \ 1321ab978335SPeter Maydell } 1322ab978335SPeter Maydell 1323ab978335SPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds) 1324ab978335SPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs) 1325ab978335SPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins) 1326d3c8c736SPeter Maydell 1327d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1328d3c8c736SPeter Maydell { 1329d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1330d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1331d3c8c736SPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 1332d3c8c736SPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 1333d3c8c736SPeter Maydell 1334d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1335d3c8c736SPeter Maydell return false; 1336d3c8c736SPeter Maydell } 1337d3c8c736SPeter Maydell 1338d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1339d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1340d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1341d3c8c736SPeter Maydell return false; 1342d3c8c736SPeter Maydell } 1343d3c8c736SPeter Maydell 1344d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1345d3c8c736SPeter Maydell return false; 1346d3c8c736SPeter Maydell } 1347d3c8c736SPeter Maydell 1348d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1349d3c8c736SPeter Maydell return true; 1350d3c8c736SPeter Maydell } 1351d3c8c736SPeter Maydell 1352d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1353d3c8c736SPeter Maydell return true; 1354d3c8c736SPeter Maydell } 1355d3c8c736SPeter Maydell 1356d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1357d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1358d3c8c736SPeter Maydell { \ 1359d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1360d3c8c736SPeter Maydell } \ 1361d3c8c736SPeter Maydell 1362d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1363d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1364434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1365434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1366434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1367434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1368434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1369434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1370434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 137166432d6bSPeter Maydell 137266432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 137366432d6bSPeter Maydell { 137466432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 137566432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 137666432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 137766432d6bSPeter Maydell } 137866432d6bSPeter Maydell 137966432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 138066432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 138166432d6bSPeter Maydell { 138266432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 138366432d6bSPeter Maydell } 138466432d6bSPeter Maydell 138566432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 138666432d6bSPeter Maydell { 138766432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 138866432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 138966432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 139066432d6bSPeter Maydell } else { 139166432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 139266432d6bSPeter Maydell } 139366432d6bSPeter Maydell } 139437bfce81SPeter Maydell 139537bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 139637bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 139737bfce81SPeter Maydell { 139837bfce81SPeter Maydell /* 139937bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 140037bfce81SPeter Maydell * function needs to be passed cpu_env. 140137bfce81SPeter Maydell */ 140237bfce81SPeter Maydell TCGv_i64 constimm; 140337bfce81SPeter Maydell int pass; 140437bfce81SPeter Maydell 140537bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 140637bfce81SPeter Maydell return false; 140737bfce81SPeter Maydell } 140837bfce81SPeter Maydell 140937bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 141037bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 141137bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 141237bfce81SPeter Maydell return false; 141337bfce81SPeter Maydell } 141437bfce81SPeter Maydell 141537bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 141637bfce81SPeter Maydell return false; 141737bfce81SPeter Maydell } 141837bfce81SPeter Maydell 141937bfce81SPeter Maydell if (!vfp_access_check(s)) { 142037bfce81SPeter Maydell return true; 142137bfce81SPeter Maydell } 142237bfce81SPeter Maydell 142337bfce81SPeter Maydell /* 142437bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 142537bfce81SPeter Maydell * by immediate using the variable shift operations. 142637bfce81SPeter Maydell */ 142737bfce81SPeter Maydell constimm = tcg_const_i64(dup_const(a->size, a->shift)); 142837bfce81SPeter Maydell 142937bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 143037bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 143137bfce81SPeter Maydell 143237bfce81SPeter Maydell neon_load_reg64(tmp, a->vm + pass); 143337bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 143437bfce81SPeter Maydell neon_store_reg64(tmp, a->vd + pass); 1435a4f67e18SPeter Maydell tcg_temp_free_i64(tmp); 143637bfce81SPeter Maydell } 143737bfce81SPeter Maydell tcg_temp_free_i64(constimm); 143837bfce81SPeter Maydell return true; 143937bfce81SPeter Maydell } 144037bfce81SPeter Maydell 144137bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 144237bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 144337bfce81SPeter Maydell { 144437bfce81SPeter Maydell /* 144537bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 144637bfce81SPeter Maydell * helper needs to be passed cpu_env. 144737bfce81SPeter Maydell */ 144837bfce81SPeter Maydell TCGv_i32 constimm; 144937bfce81SPeter Maydell int pass; 145037bfce81SPeter Maydell 145137bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 145237bfce81SPeter Maydell return false; 145337bfce81SPeter Maydell } 145437bfce81SPeter Maydell 145537bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 145637bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 145737bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 145837bfce81SPeter Maydell return false; 145937bfce81SPeter Maydell } 146037bfce81SPeter Maydell 146137bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 146237bfce81SPeter Maydell return false; 146337bfce81SPeter Maydell } 146437bfce81SPeter Maydell 146537bfce81SPeter Maydell if (!vfp_access_check(s)) { 146637bfce81SPeter Maydell return true; 146737bfce81SPeter Maydell } 146837bfce81SPeter Maydell 146937bfce81SPeter Maydell /* 147037bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 147137bfce81SPeter Maydell * by immediate using the variable shift operations. 147237bfce81SPeter Maydell */ 147337bfce81SPeter Maydell constimm = tcg_const_i32(dup_const(a->size, a->shift)); 147437bfce81SPeter Maydell 147537bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 147637bfce81SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 147737bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 147837bfce81SPeter Maydell neon_store_reg(a->vd, pass, tmp); 147937bfce81SPeter Maydell } 148037bfce81SPeter Maydell tcg_temp_free_i32(constimm); 148137bfce81SPeter Maydell return true; 148237bfce81SPeter Maydell } 148337bfce81SPeter Maydell 148437bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 148537bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 148637bfce81SPeter Maydell { \ 148737bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 148837bfce81SPeter Maydell } \ 148937bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 149037bfce81SPeter Maydell { \ 149137bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 149237bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 149337bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 149437bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 149537bfce81SPeter Maydell }; \ 149637bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 149737bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 149837bfce81SPeter Maydell } 149937bfce81SPeter Maydell 150037bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 150137bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 150237bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1503712182d3SPeter Maydell 1504712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1505712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1506712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1507712182d3SPeter Maydell { 1508712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1509712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1510712182d3SPeter Maydell TCGv_i32 rd; 1511712182d3SPeter Maydell 1512712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1513712182d3SPeter Maydell return false; 1514712182d3SPeter Maydell } 1515712182d3SPeter Maydell 1516712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1517712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1518712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1519712182d3SPeter Maydell return false; 1520712182d3SPeter Maydell } 1521712182d3SPeter Maydell 1522712182d3SPeter Maydell if (a->vm & 1) { 1523712182d3SPeter Maydell return false; 1524712182d3SPeter Maydell } 1525712182d3SPeter Maydell 1526712182d3SPeter Maydell if (!vfp_access_check(s)) { 1527712182d3SPeter Maydell return true; 1528712182d3SPeter Maydell } 1529712182d3SPeter Maydell 1530712182d3SPeter Maydell /* 1531712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1532712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1533712182d3SPeter Maydell */ 1534712182d3SPeter Maydell constimm = tcg_const_i64(-a->shift); 1535712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1536712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1537712182d3SPeter Maydell 1538712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 1539712182d3SPeter Maydell neon_load_reg64(rm1, a->vm); 1540712182d3SPeter Maydell neon_load_reg64(rm2, a->vm + 1); 1541712182d3SPeter Maydell 1542712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1543712182d3SPeter Maydell rd = tcg_temp_new_i32(); 1544712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1545712182d3SPeter Maydell neon_store_reg(a->vd, 0, rd); 1546712182d3SPeter Maydell 1547712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1548712182d3SPeter Maydell rd = tcg_temp_new_i32(); 1549712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1550712182d3SPeter Maydell neon_store_reg(a->vd, 1, rd); 1551712182d3SPeter Maydell 1552712182d3SPeter Maydell tcg_temp_free_i64(rm1); 1553712182d3SPeter Maydell tcg_temp_free_i64(rm2); 1554712182d3SPeter Maydell tcg_temp_free_i64(constimm); 1555712182d3SPeter Maydell 1556712182d3SPeter Maydell return true; 1557712182d3SPeter Maydell } 1558712182d3SPeter Maydell 1559712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1560712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1561712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1562712182d3SPeter Maydell { 1563712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1564712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1565712182d3SPeter Maydell TCGv_i64 rtmp; 1566712182d3SPeter Maydell uint32_t imm; 1567712182d3SPeter Maydell 1568712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1569712182d3SPeter Maydell return false; 1570712182d3SPeter Maydell } 1571712182d3SPeter Maydell 1572712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1573712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1574712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1575712182d3SPeter Maydell return false; 1576712182d3SPeter Maydell } 1577712182d3SPeter Maydell 1578712182d3SPeter Maydell if (a->vm & 1) { 1579712182d3SPeter Maydell return false; 1580712182d3SPeter Maydell } 1581712182d3SPeter Maydell 1582712182d3SPeter Maydell if (!vfp_access_check(s)) { 1583712182d3SPeter Maydell return true; 1584712182d3SPeter Maydell } 1585712182d3SPeter Maydell 1586712182d3SPeter Maydell /* 1587712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1588712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1589712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1590712182d3SPeter Maydell */ 1591712182d3SPeter Maydell if (a->size == 1) { 1592712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1593712182d3SPeter Maydell imm |= imm << 16; 1594712182d3SPeter Maydell } else { 1595712182d3SPeter Maydell /* size == 2 */ 1596712182d3SPeter Maydell imm = -a->shift; 1597712182d3SPeter Maydell } 1598712182d3SPeter Maydell constimm = tcg_const_i32(imm); 1599712182d3SPeter Maydell 1600712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1601712182d3SPeter Maydell rm1 = neon_load_reg(a->vm, 0); 1602712182d3SPeter Maydell rm2 = neon_load_reg(a->vm, 1); 1603712182d3SPeter Maydell rm3 = neon_load_reg(a->vm + 1, 0); 1604712182d3SPeter Maydell rm4 = neon_load_reg(a->vm + 1, 1); 1605712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1606712182d3SPeter Maydell 1607712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1608712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1609712182d3SPeter Maydell 1610712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1611712182d3SPeter Maydell tcg_temp_free_i32(rm2); 1612712182d3SPeter Maydell 1613712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1614712182d3SPeter Maydell neon_store_reg(a->vd, 0, rm1); 1615712182d3SPeter Maydell 1616712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1617712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1618712182d3SPeter Maydell tcg_temp_free_i32(constimm); 1619712182d3SPeter Maydell 1620712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1621712182d3SPeter Maydell tcg_temp_free_i32(rm4); 1622712182d3SPeter Maydell 1623712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1624712182d3SPeter Maydell tcg_temp_free_i64(rtmp); 1625712182d3SPeter Maydell neon_store_reg(a->vd, 1, rm3); 1626712182d3SPeter Maydell return true; 1627712182d3SPeter Maydell } 1628712182d3SPeter Maydell 1629712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1630712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1631712182d3SPeter Maydell { \ 1632712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1633712182d3SPeter Maydell } 1634712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1635712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1636712182d3SPeter Maydell { \ 1637712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1638712182d3SPeter Maydell } 1639712182d3SPeter Maydell 1640712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1641712182d3SPeter Maydell { 1642712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1643712182d3SPeter Maydell } 1644712182d3SPeter Maydell 1645712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1646712182d3SPeter Maydell { 1647712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1648712182d3SPeter Maydell } 1649712182d3SPeter Maydell 1650712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1651712182d3SPeter Maydell { 1652712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1653712182d3SPeter Maydell } 1654712182d3SPeter Maydell 1655712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1656712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1657712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1658712182d3SPeter Maydell 1659712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1660712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1661712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1662712182d3SPeter Maydell 1663712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1664712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1665712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1666712182d3SPeter Maydell 1667712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1668712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1669712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1670b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1671b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1672b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1673b4a3a77bSPeter Maydell 1674b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1675b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1676b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1677b4a3a77bSPeter Maydell 1678b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1679b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1680b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1681b4a3a77bSPeter Maydell 1682b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1683b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1684b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1685968bf842SPeter Maydell 1686968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1687968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1688968bf842SPeter Maydell { 1689968bf842SPeter Maydell TCGv_i64 tmp; 1690968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1691968bf842SPeter Maydell uint64_t widen_mask = 0; 1692968bf842SPeter Maydell 1693968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1694968bf842SPeter Maydell return false; 1695968bf842SPeter Maydell } 1696968bf842SPeter Maydell 1697968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1698968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1699968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1700968bf842SPeter Maydell return false; 1701968bf842SPeter Maydell } 1702968bf842SPeter Maydell 1703968bf842SPeter Maydell if (a->vd & 1) { 1704968bf842SPeter Maydell return false; 1705968bf842SPeter Maydell } 1706968bf842SPeter Maydell 1707968bf842SPeter Maydell if (!vfp_access_check(s)) { 1708968bf842SPeter Maydell return true; 1709968bf842SPeter Maydell } 1710968bf842SPeter Maydell 1711968bf842SPeter Maydell /* 1712968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1713968bf842SPeter Maydell * than the width of the source type, so after widening the input 1714968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1715968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1716968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1717968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1718968bf842SPeter Maydell */ 1719968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1720968bf842SPeter Maydell int esize = 8 << a->size; 1721968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1722968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1723968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1724968bf842SPeter Maydell } 1725968bf842SPeter Maydell 1726968bf842SPeter Maydell rm0 = neon_load_reg(a->vm, 0); 1727968bf842SPeter Maydell rm1 = neon_load_reg(a->vm, 1); 1728968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1729968bf842SPeter Maydell 1730968bf842SPeter Maydell widenfn(tmp, rm0); 17319593a398SPeter Maydell tcg_temp_free_i32(rm0); 1732968bf842SPeter Maydell if (a->shift != 0) { 1733968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1734968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1735968bf842SPeter Maydell } 1736968bf842SPeter Maydell neon_store_reg64(tmp, a->vd); 1737968bf842SPeter Maydell 1738968bf842SPeter Maydell widenfn(tmp, rm1); 17399593a398SPeter Maydell tcg_temp_free_i32(rm1); 1740968bf842SPeter Maydell if (a->shift != 0) { 1741968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1742968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1743968bf842SPeter Maydell } 1744968bf842SPeter Maydell neon_store_reg64(tmp, a->vd + 1); 1745968bf842SPeter Maydell tcg_temp_free_i64(tmp); 1746968bf842SPeter Maydell return true; 1747968bf842SPeter Maydell } 1748968bf842SPeter Maydell 1749968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1750968bf842SPeter Maydell { 1751448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1752968bf842SPeter Maydell gen_helper_neon_widen_s8, 1753968bf842SPeter Maydell gen_helper_neon_widen_s16, 1754968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1755968bf842SPeter Maydell }; 1756968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1757968bf842SPeter Maydell } 1758968bf842SPeter Maydell 1759968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1760968bf842SPeter Maydell { 1761448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1762968bf842SPeter Maydell gen_helper_neon_widen_u8, 1763968bf842SPeter Maydell gen_helper_neon_widen_u16, 1764968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1765968bf842SPeter Maydell }; 1766968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1767968bf842SPeter Maydell } 17683da26f11SPeter Maydell 17693da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 17705de3fd04SPeter Maydell NeonGenTwoSingleOpFn *fn) 17713da26f11SPeter Maydell { 17723da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 17733da26f11SPeter Maydell TCGv_i32 tmp, shiftv; 17743da26f11SPeter Maydell TCGv_ptr fpstatus; 17753da26f11SPeter Maydell int pass; 17763da26f11SPeter Maydell 17773da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17783da26f11SPeter Maydell return false; 17793da26f11SPeter Maydell } 17803da26f11SPeter Maydell 17813da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17823da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 17833da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 17843da26f11SPeter Maydell return false; 17853da26f11SPeter Maydell } 17863da26f11SPeter Maydell 17873da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 17883da26f11SPeter Maydell return false; 17893da26f11SPeter Maydell } 17903da26f11SPeter Maydell 17913da26f11SPeter Maydell if (!vfp_access_check(s)) { 17923da26f11SPeter Maydell return true; 17933da26f11SPeter Maydell } 17943da26f11SPeter Maydell 1795a84d1d13SPeter Maydell fpstatus = fpstatus_ptr(FPST_STD); 17963da26f11SPeter Maydell shiftv = tcg_const_i32(a->shift); 17973da26f11SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 17983da26f11SPeter Maydell tmp = neon_load_reg(a->vm, pass); 17993da26f11SPeter Maydell fn(tmp, tmp, shiftv, fpstatus); 18003da26f11SPeter Maydell neon_store_reg(a->vd, pass, tmp); 18013da26f11SPeter Maydell } 18023da26f11SPeter Maydell tcg_temp_free_ptr(fpstatus); 18033da26f11SPeter Maydell tcg_temp_free_i32(shiftv); 18043da26f11SPeter Maydell return true; 18053da26f11SPeter Maydell } 18063da26f11SPeter Maydell 18073da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 18083da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 18093da26f11SPeter Maydell { \ 18103da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 18113da26f11SPeter Maydell } 18123da26f11SPeter Maydell 18133da26f11SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos) 18143da26f11SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos) 18153da26f11SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero) 18163da26f11SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero) 18172c35a39eSPeter Maydell 18182c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) 18192c35a39eSPeter Maydell { 18202c35a39eSPeter Maydell /* 18212c35a39eSPeter Maydell * Expand the encoded constant. 18222c35a39eSPeter Maydell * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. 18232c35a39eSPeter Maydell * We choose to not special-case this and will behave as if a 18242c35a39eSPeter Maydell * valid constant encoding of 0 had been given. 18252c35a39eSPeter Maydell * cmode = 15 op = 1 must UNDEF; we assume decode has handled that. 18262c35a39eSPeter Maydell */ 18272c35a39eSPeter Maydell switch (cmode) { 18282c35a39eSPeter Maydell case 0: case 1: 18292c35a39eSPeter Maydell /* no-op */ 18302c35a39eSPeter Maydell break; 18312c35a39eSPeter Maydell case 2: case 3: 18322c35a39eSPeter Maydell imm <<= 8; 18332c35a39eSPeter Maydell break; 18342c35a39eSPeter Maydell case 4: case 5: 18352c35a39eSPeter Maydell imm <<= 16; 18362c35a39eSPeter Maydell break; 18372c35a39eSPeter Maydell case 6: case 7: 18382c35a39eSPeter Maydell imm <<= 24; 18392c35a39eSPeter Maydell break; 18402c35a39eSPeter Maydell case 8: case 9: 18412c35a39eSPeter Maydell imm |= imm << 16; 18422c35a39eSPeter Maydell break; 18432c35a39eSPeter Maydell case 10: case 11: 18442c35a39eSPeter Maydell imm = (imm << 8) | (imm << 24); 18452c35a39eSPeter Maydell break; 18462c35a39eSPeter Maydell case 12: 18472c35a39eSPeter Maydell imm = (imm << 8) | 0xff; 18482c35a39eSPeter Maydell break; 18492c35a39eSPeter Maydell case 13: 18502c35a39eSPeter Maydell imm = (imm << 16) | 0xffff; 18512c35a39eSPeter Maydell break; 18522c35a39eSPeter Maydell case 14: 18532c35a39eSPeter Maydell if (op) { 18542c35a39eSPeter Maydell /* 18552c35a39eSPeter Maydell * This is the only case where the top and bottom 32 bits 18562c35a39eSPeter Maydell * of the encoded constant differ. 18572c35a39eSPeter Maydell */ 18582c35a39eSPeter Maydell uint64_t imm64 = 0; 18592c35a39eSPeter Maydell int n; 18602c35a39eSPeter Maydell 18612c35a39eSPeter Maydell for (n = 0; n < 8; n++) { 18622c35a39eSPeter Maydell if (imm & (1 << n)) { 18632c35a39eSPeter Maydell imm64 |= (0xffULL << (n * 8)); 18642c35a39eSPeter Maydell } 18652c35a39eSPeter Maydell } 18662c35a39eSPeter Maydell return imm64; 18672c35a39eSPeter Maydell } 18682c35a39eSPeter Maydell imm |= (imm << 8) | (imm << 16) | (imm << 24); 18692c35a39eSPeter Maydell break; 18702c35a39eSPeter Maydell case 15: 18712c35a39eSPeter Maydell imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) 18722c35a39eSPeter Maydell | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); 18732c35a39eSPeter Maydell break; 18742c35a39eSPeter Maydell } 18752c35a39eSPeter Maydell if (op) { 18762c35a39eSPeter Maydell imm = ~imm; 18772c35a39eSPeter Maydell } 18782c35a39eSPeter Maydell return dup_const(MO_32, imm); 18792c35a39eSPeter Maydell } 18802c35a39eSPeter Maydell 18812c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 18822c35a39eSPeter Maydell GVecGen2iFn *fn) 18832c35a39eSPeter Maydell { 18842c35a39eSPeter Maydell uint64_t imm; 18852c35a39eSPeter Maydell int reg_ofs, vec_size; 18862c35a39eSPeter Maydell 18872c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 18882c35a39eSPeter Maydell return false; 18892c35a39eSPeter Maydell } 18902c35a39eSPeter Maydell 18912c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 18922c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 18932c35a39eSPeter Maydell return false; 18942c35a39eSPeter Maydell } 18952c35a39eSPeter Maydell 18962c35a39eSPeter Maydell if (a->vd & a->q) { 18972c35a39eSPeter Maydell return false; 18982c35a39eSPeter Maydell } 18992c35a39eSPeter Maydell 19002c35a39eSPeter Maydell if (!vfp_access_check(s)) { 19012c35a39eSPeter Maydell return true; 19022c35a39eSPeter Maydell } 19032c35a39eSPeter Maydell 19042c35a39eSPeter Maydell reg_ofs = neon_reg_offset(a->vd, 0); 19052c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 19062c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 19072c35a39eSPeter Maydell 19082c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 19092c35a39eSPeter Maydell return true; 19102c35a39eSPeter Maydell } 19112c35a39eSPeter Maydell 19122c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 19132c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 19142c35a39eSPeter Maydell { 19152c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 19162c35a39eSPeter Maydell } 19172c35a39eSPeter Maydell 19182c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 19192c35a39eSPeter Maydell { 19202c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 19212c35a39eSPeter Maydell GVecGen2iFn *fn; 19222c35a39eSPeter Maydell 19232c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 19242c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 19252c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 19262c35a39eSPeter Maydell } else { 19272c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 19282c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 19292c35a39eSPeter Maydell return false; 19302c35a39eSPeter Maydell } 19312c35a39eSPeter Maydell fn = gen_VMOV_1r; 19322c35a39eSPeter Maydell } 19332c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 19342c35a39eSPeter Maydell } 1935b28be095SPeter Maydell 1936b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1937b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1938b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 1939b28be095SPeter Maydell bool src1_wide) 1940b28be095SPeter Maydell { 1941b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1942b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1943b28be095SPeter Maydell TCGv_i32 rm; 1944b28be095SPeter Maydell 1945b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1946b28be095SPeter Maydell return false; 1947b28be095SPeter Maydell } 1948b28be095SPeter Maydell 1949b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1950b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1951b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1952b28be095SPeter Maydell return false; 1953b28be095SPeter Maydell } 1954b28be095SPeter Maydell 1955b28be095SPeter Maydell if (!widenfn || !opfn) { 1956b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1957b28be095SPeter Maydell return false; 1958b28be095SPeter Maydell } 1959b28be095SPeter Maydell 1960b28be095SPeter Maydell if ((a->vd & 1) || (src1_wide && (a->vn & 1))) { 1961b28be095SPeter Maydell return false; 1962b28be095SPeter Maydell } 1963b28be095SPeter Maydell 1964b28be095SPeter Maydell if (!vfp_access_check(s)) { 1965b28be095SPeter Maydell return true; 1966b28be095SPeter Maydell } 1967b28be095SPeter Maydell 1968b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1969b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1970b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1971b28be095SPeter Maydell 1972b28be095SPeter Maydell if (src1_wide) { 1973b28be095SPeter Maydell neon_load_reg64(rn0_64, a->vn); 1974b28be095SPeter Maydell } else { 1975b28be095SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, 0); 1976b28be095SPeter Maydell widenfn(rn0_64, tmp); 1977b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1978b28be095SPeter Maydell } 1979b28be095SPeter Maydell rm = neon_load_reg(a->vm, 0); 1980b28be095SPeter Maydell 1981b28be095SPeter Maydell widenfn(rm_64, rm); 1982b28be095SPeter Maydell tcg_temp_free_i32(rm); 1983b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1984b28be095SPeter Maydell 1985b28be095SPeter Maydell /* 1986b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1987b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1988b28be095SPeter Maydell */ 1989b28be095SPeter Maydell if (src1_wide) { 1990b28be095SPeter Maydell neon_load_reg64(rn1_64, a->vn + 1); 1991b28be095SPeter Maydell } else { 1992b28be095SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, 1); 1993b28be095SPeter Maydell widenfn(rn1_64, tmp); 1994b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1995b28be095SPeter Maydell } 1996b28be095SPeter Maydell rm = neon_load_reg(a->vm, 1); 1997b28be095SPeter Maydell 1998b28be095SPeter Maydell neon_store_reg64(rn0_64, a->vd); 1999b28be095SPeter Maydell 2000b28be095SPeter Maydell widenfn(rm_64, rm); 2001b28be095SPeter Maydell tcg_temp_free_i32(rm); 2002b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 2003b28be095SPeter Maydell neon_store_reg64(rn1_64, a->vd + 1); 2004b28be095SPeter Maydell 2005b28be095SPeter Maydell tcg_temp_free_i64(rn0_64); 2006b28be095SPeter Maydell tcg_temp_free_i64(rn1_64); 2007b28be095SPeter Maydell tcg_temp_free_i64(rm_64); 2008b28be095SPeter Maydell 2009b28be095SPeter Maydell return true; 2010b28be095SPeter Maydell } 2011b28be095SPeter Maydell 2012b28be095SPeter Maydell #define DO_PREWIDEN(INSN, S, EXT, OP, SRC1WIDE) \ 2013b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 2014b28be095SPeter Maydell { \ 2015b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 2016b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 2017b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 2018b28be095SPeter Maydell tcg_gen_##EXT##_i32_i64, \ 2019b28be095SPeter Maydell NULL, \ 2020b28be095SPeter Maydell }; \ 2021b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 2022b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 2023b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 2024b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 2025b28be095SPeter Maydell NULL, \ 2026b28be095SPeter Maydell }; \ 2027b28be095SPeter Maydell return do_prewiden_3d(s, a, widenfn[a->size], \ 2028b28be095SPeter Maydell addfn[a->size], SRC1WIDE); \ 2029b28be095SPeter Maydell } 2030b28be095SPeter Maydell 2031b28be095SPeter Maydell DO_PREWIDEN(VADDL_S, s, ext, add, false) 2032b28be095SPeter Maydell DO_PREWIDEN(VADDL_U, u, extu, add, false) 2033b28be095SPeter Maydell DO_PREWIDEN(VSUBL_S, s, ext, sub, false) 2034b28be095SPeter Maydell DO_PREWIDEN(VSUBL_U, u, extu, sub, false) 2035b28be095SPeter Maydell DO_PREWIDEN(VADDW_S, s, ext, add, true) 2036b28be095SPeter Maydell DO_PREWIDEN(VADDW_U, u, extu, add, true) 2037b28be095SPeter Maydell DO_PREWIDEN(VSUBW_S, s, ext, sub, true) 2038b28be095SPeter Maydell DO_PREWIDEN(VSUBW_U, u, extu, sub, true) 20390fa1ab03SPeter Maydell 20400fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 20410fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 20420fa1ab03SPeter Maydell { 20430fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 20440fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 20450fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 20460fa1ab03SPeter Maydell 20470fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 20480fa1ab03SPeter Maydell return false; 20490fa1ab03SPeter Maydell } 20500fa1ab03SPeter Maydell 20510fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 20520fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 20530fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 20540fa1ab03SPeter Maydell return false; 20550fa1ab03SPeter Maydell } 20560fa1ab03SPeter Maydell 20570fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 20580fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 20590fa1ab03SPeter Maydell return false; 20600fa1ab03SPeter Maydell } 20610fa1ab03SPeter Maydell 20620fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 20630fa1ab03SPeter Maydell return false; 20640fa1ab03SPeter Maydell } 20650fa1ab03SPeter Maydell 20660fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 20670fa1ab03SPeter Maydell return true; 20680fa1ab03SPeter Maydell } 20690fa1ab03SPeter Maydell 20700fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 20710fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 20720fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 20730fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 20740fa1ab03SPeter Maydell 20750fa1ab03SPeter Maydell neon_load_reg64(rn_64, a->vn); 20760fa1ab03SPeter Maydell neon_load_reg64(rm_64, a->vm); 20770fa1ab03SPeter Maydell 20780fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 20790fa1ab03SPeter Maydell 20800fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 20810fa1ab03SPeter Maydell 20820fa1ab03SPeter Maydell neon_load_reg64(rn_64, a->vn + 1); 20830fa1ab03SPeter Maydell neon_load_reg64(rm_64, a->vm + 1); 20840fa1ab03SPeter Maydell 20850fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 20860fa1ab03SPeter Maydell 20870fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 20880fa1ab03SPeter Maydell 20890fa1ab03SPeter Maydell neon_store_reg(a->vd, 0, rd0); 20900fa1ab03SPeter Maydell neon_store_reg(a->vd, 1, rd1); 20910fa1ab03SPeter Maydell 20920fa1ab03SPeter Maydell tcg_temp_free_i64(rn_64); 20930fa1ab03SPeter Maydell tcg_temp_free_i64(rm_64); 20940fa1ab03SPeter Maydell 20950fa1ab03SPeter Maydell return true; 20960fa1ab03SPeter Maydell } 20970fa1ab03SPeter Maydell 20980fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 20990fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 21000fa1ab03SPeter Maydell { \ 21010fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 21020fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 21030fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 21040fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 21050fa1ab03SPeter Maydell NULL, \ 21060fa1ab03SPeter Maydell }; \ 21070fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 21080fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 21090fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 21100fa1ab03SPeter Maydell EXTOP, \ 21110fa1ab03SPeter Maydell NULL, \ 21120fa1ab03SPeter Maydell }; \ 21130fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 21140fa1ab03SPeter Maydell } 21150fa1ab03SPeter Maydell 21160fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 21170fa1ab03SPeter Maydell { 21180fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 21190fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 21200fa1ab03SPeter Maydell } 21210fa1ab03SPeter Maydell 21220fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 21230fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 21240fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 21250fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 2126f5b28401SPeter Maydell 2127f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 2128f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 2129f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 2130f5b28401SPeter Maydell { 2131f5b28401SPeter Maydell /* 2132f5b28401SPeter Maydell * 3-regs different lengths, long operations. 2133f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 2134f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 2135f5b28401SPeter Maydell * that result into the double-width destination. 2136f5b28401SPeter Maydell */ 2137f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 2138f5b28401SPeter Maydell TCGv_i32 rn, rm; 2139f5b28401SPeter Maydell 2140f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2141f5b28401SPeter Maydell return false; 2142f5b28401SPeter Maydell } 2143f5b28401SPeter Maydell 2144f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2145f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2146f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2147f5b28401SPeter Maydell return false; 2148f5b28401SPeter Maydell } 2149f5b28401SPeter Maydell 2150f5b28401SPeter Maydell if (!opfn) { 2151f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 2152f5b28401SPeter Maydell return false; 2153f5b28401SPeter Maydell } 2154f5b28401SPeter Maydell 2155f5b28401SPeter Maydell if (a->vd & 1) { 2156f5b28401SPeter Maydell return false; 2157f5b28401SPeter Maydell } 2158f5b28401SPeter Maydell 2159f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2160f5b28401SPeter Maydell return true; 2161f5b28401SPeter Maydell } 2162f5b28401SPeter Maydell 2163f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2164f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2165f5b28401SPeter Maydell 2166f5b28401SPeter Maydell rn = neon_load_reg(a->vn, 0); 2167f5b28401SPeter Maydell rm = neon_load_reg(a->vm, 0); 2168f5b28401SPeter Maydell opfn(rd0, rn, rm); 2169f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2170f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2171f5b28401SPeter Maydell 2172f5b28401SPeter Maydell rn = neon_load_reg(a->vn, 1); 2173f5b28401SPeter Maydell rm = neon_load_reg(a->vm, 1); 2174f5b28401SPeter Maydell opfn(rd1, rn, rm); 2175f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2176f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2177f5b28401SPeter Maydell 2178f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2179f5b28401SPeter Maydell if (accfn) { 2180f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 2181f5b28401SPeter Maydell neon_load_reg64(tmp, a->vd); 2182f5b28401SPeter Maydell accfn(tmp, tmp, rd0); 2183f5b28401SPeter Maydell neon_store_reg64(tmp, a->vd); 2184f5b28401SPeter Maydell neon_load_reg64(tmp, a->vd + 1); 2185f5b28401SPeter Maydell accfn(tmp, tmp, rd1); 2186f5b28401SPeter Maydell neon_store_reg64(tmp, a->vd + 1); 2187f5b28401SPeter Maydell tcg_temp_free_i64(tmp); 2188f5b28401SPeter Maydell } else { 2189f5b28401SPeter Maydell neon_store_reg64(rd0, a->vd); 2190f5b28401SPeter Maydell neon_store_reg64(rd1, a->vd + 1); 2191f5b28401SPeter Maydell } 2192f5b28401SPeter Maydell 2193f5b28401SPeter Maydell tcg_temp_free_i64(rd0); 2194f5b28401SPeter Maydell tcg_temp_free_i64(rd1); 2195f5b28401SPeter Maydell 2196f5b28401SPeter Maydell return true; 2197f5b28401SPeter Maydell } 2198f5b28401SPeter Maydell 2199f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2200f5b28401SPeter Maydell { 2201f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2202f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2203f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2204f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2205f5b28401SPeter Maydell NULL, 2206f5b28401SPeter Maydell }; 2207f5b28401SPeter Maydell 2208f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2209f5b28401SPeter Maydell } 2210f5b28401SPeter Maydell 2211f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2212f5b28401SPeter Maydell { 2213f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2214f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2215f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2216f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2217f5b28401SPeter Maydell NULL, 2218f5b28401SPeter Maydell }; 2219f5b28401SPeter Maydell 2220f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2221f5b28401SPeter Maydell } 2222f5b28401SPeter Maydell 2223f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2224f5b28401SPeter Maydell { 2225f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2226f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2227f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2228f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2229f5b28401SPeter Maydell NULL, 2230f5b28401SPeter Maydell }; 2231f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2232f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2233f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2234f5b28401SPeter Maydell tcg_gen_add_i64, 2235f5b28401SPeter Maydell NULL, 2236f5b28401SPeter Maydell }; 2237f5b28401SPeter Maydell 2238f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2239f5b28401SPeter Maydell } 2240f5b28401SPeter Maydell 2241f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2242f5b28401SPeter Maydell { 2243f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2244f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2245f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2246f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2247f5b28401SPeter Maydell NULL, 2248f5b28401SPeter Maydell }; 2249f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2250f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2251f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2252f5b28401SPeter Maydell tcg_gen_add_i64, 2253f5b28401SPeter Maydell NULL, 2254f5b28401SPeter Maydell }; 2255f5b28401SPeter Maydell 2256f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2257f5b28401SPeter Maydell } 22583a1d9eb0SPeter Maydell 22593a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22603a1d9eb0SPeter Maydell { 22613a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 22623a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 22633a1d9eb0SPeter Maydell 22643a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 22653a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 22663a1d9eb0SPeter Maydell 22673a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 22683a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 22693a1d9eb0SPeter Maydell } 22703a1d9eb0SPeter Maydell 22713a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22723a1d9eb0SPeter Maydell { 22733a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 22743a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 22753a1d9eb0SPeter Maydell 22763a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 22773a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 22783a1d9eb0SPeter Maydell 22793a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 22803a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 22813a1d9eb0SPeter Maydell } 22823a1d9eb0SPeter Maydell 22833a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 22843a1d9eb0SPeter Maydell { 22853a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22863a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 22873a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 22883a1d9eb0SPeter Maydell gen_mull_s32, 22893a1d9eb0SPeter Maydell NULL, 22903a1d9eb0SPeter Maydell }; 22913a1d9eb0SPeter Maydell 22923a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22933a1d9eb0SPeter Maydell } 22943a1d9eb0SPeter Maydell 22953a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 22963a1d9eb0SPeter Maydell { 22973a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22983a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 22993a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 23003a1d9eb0SPeter Maydell gen_mull_u32, 23013a1d9eb0SPeter Maydell NULL, 23023a1d9eb0SPeter Maydell }; 23033a1d9eb0SPeter Maydell 23043a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 23053a1d9eb0SPeter Maydell } 23063a1d9eb0SPeter Maydell 23073a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 23083a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 23093a1d9eb0SPeter Maydell { \ 23103a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 23113a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 23123a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 23133a1d9eb0SPeter Maydell gen_##MULL##32, \ 23143a1d9eb0SPeter Maydell NULL, \ 23153a1d9eb0SPeter Maydell }; \ 23163a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 23173a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 23183a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 23193a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 23203a1d9eb0SPeter Maydell NULL, \ 23213a1d9eb0SPeter Maydell }; \ 23223a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 23233a1d9eb0SPeter Maydell } 23243a1d9eb0SPeter Maydell 23253a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 23263a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 23273a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 23283a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 23299546ca59SPeter Maydell 23309546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 23319546ca59SPeter Maydell { 23329546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 23339546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 23349546ca59SPeter Maydell } 23359546ca59SPeter Maydell 23369546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 23379546ca59SPeter Maydell { 23389546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 23399546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 23409546ca59SPeter Maydell } 23419546ca59SPeter Maydell 23429546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 23439546ca59SPeter Maydell { 23449546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23459546ca59SPeter Maydell NULL, 23469546ca59SPeter Maydell gen_VQDMULL_16, 23479546ca59SPeter Maydell gen_VQDMULL_32, 23489546ca59SPeter Maydell NULL, 23499546ca59SPeter Maydell }; 23509546ca59SPeter Maydell 23519546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 23529546ca59SPeter Maydell } 23539546ca59SPeter Maydell 23549546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23559546ca59SPeter Maydell { 23569546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 23579546ca59SPeter Maydell } 23589546ca59SPeter Maydell 23599546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23609546ca59SPeter Maydell { 23619546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 23629546ca59SPeter Maydell } 23639546ca59SPeter Maydell 23649546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 23659546ca59SPeter Maydell { 23669546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23679546ca59SPeter Maydell NULL, 23689546ca59SPeter Maydell gen_VQDMULL_16, 23699546ca59SPeter Maydell gen_VQDMULL_32, 23709546ca59SPeter Maydell NULL, 23719546ca59SPeter Maydell }; 23729546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 23739546ca59SPeter Maydell NULL, 23749546ca59SPeter Maydell gen_VQDMLAL_acc_16, 23759546ca59SPeter Maydell gen_VQDMLAL_acc_32, 23769546ca59SPeter Maydell NULL, 23779546ca59SPeter Maydell }; 23789546ca59SPeter Maydell 23799546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 23809546ca59SPeter Maydell } 23819546ca59SPeter Maydell 23829546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23839546ca59SPeter Maydell { 23849546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 23859546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 23869546ca59SPeter Maydell } 23879546ca59SPeter Maydell 23889546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 23899546ca59SPeter Maydell { 23909546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 23919546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 23929546ca59SPeter Maydell } 23939546ca59SPeter Maydell 23949546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 23959546ca59SPeter Maydell { 23969546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 23979546ca59SPeter Maydell NULL, 23989546ca59SPeter Maydell gen_VQDMULL_16, 23999546ca59SPeter Maydell gen_VQDMULL_32, 24009546ca59SPeter Maydell NULL, 24019546ca59SPeter Maydell }; 24029546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 24039546ca59SPeter Maydell NULL, 24049546ca59SPeter Maydell gen_VQDMLSL_acc_16, 24059546ca59SPeter Maydell gen_VQDMLSL_acc_32, 24069546ca59SPeter Maydell NULL, 24079546ca59SPeter Maydell }; 24089546ca59SPeter Maydell 24099546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 24109546ca59SPeter Maydell } 241118fb58d5SPeter Maydell 241218fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 241318fb58d5SPeter Maydell { 241418fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 241518fb58d5SPeter Maydell 241618fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 241718fb58d5SPeter Maydell return false; 241818fb58d5SPeter Maydell } 241918fb58d5SPeter Maydell 242018fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 242118fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 242218fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 242318fb58d5SPeter Maydell return false; 242418fb58d5SPeter Maydell } 242518fb58d5SPeter Maydell 242618fb58d5SPeter Maydell if (a->vd & 1) { 242718fb58d5SPeter Maydell return false; 242818fb58d5SPeter Maydell } 242918fb58d5SPeter Maydell 243018fb58d5SPeter Maydell switch (a->size) { 243118fb58d5SPeter Maydell case 0: 243218fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 243318fb58d5SPeter Maydell break; 243418fb58d5SPeter Maydell case 2: 243518fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 243618fb58d5SPeter Maydell return false; 243718fb58d5SPeter Maydell } 243818fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 243918fb58d5SPeter Maydell break; 244018fb58d5SPeter Maydell default: 244118fb58d5SPeter Maydell return false; 244218fb58d5SPeter Maydell } 244318fb58d5SPeter Maydell 244418fb58d5SPeter Maydell if (!vfp_access_check(s)) { 244518fb58d5SPeter Maydell return true; 244618fb58d5SPeter Maydell } 244718fb58d5SPeter Maydell 244818fb58d5SPeter Maydell tcg_gen_gvec_3_ool(neon_reg_offset(a->vd, 0), 244918fb58d5SPeter Maydell neon_reg_offset(a->vn, 0), 245018fb58d5SPeter Maydell neon_reg_offset(a->vm, 0), 245118fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 245218fb58d5SPeter Maydell return true; 245318fb58d5SPeter Maydell } 245496fc80f5SPeter Maydell 245596fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 245696fc80f5SPeter Maydell { 245796fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 245896fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 245996fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 246096fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 246196fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 246296fc80f5SPeter Maydell } 246396fc80f5SPeter Maydell 246496fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 246596fc80f5SPeter Maydell { 246696fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 246796fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 246896fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 246996fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 247096fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 247196fc80f5SPeter Maydell } 247296fc80f5SPeter Maydell 247396fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 247496fc80f5SPeter Maydell { 247596fc80f5SPeter Maydell TCGv_i32 tmp; 247696fc80f5SPeter Maydell if (size == 1) { 247796fc80f5SPeter Maydell tmp = neon_load_reg(reg & 7, reg >> 4); 247896fc80f5SPeter Maydell if (reg & 8) { 247996fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 248096fc80f5SPeter Maydell } else { 248196fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 248296fc80f5SPeter Maydell } 248396fc80f5SPeter Maydell } else { 248496fc80f5SPeter Maydell tmp = neon_load_reg(reg & 15, reg >> 4); 248596fc80f5SPeter Maydell } 248696fc80f5SPeter Maydell return tmp; 248796fc80f5SPeter Maydell } 248896fc80f5SPeter Maydell 248996fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 249096fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 249196fc80f5SPeter Maydell { 249296fc80f5SPeter Maydell /* 249396fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 249496fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 249596fc80f5SPeter Maydell * perform an accumulation operation of that result into the 249696fc80f5SPeter Maydell * destination. 249796fc80f5SPeter Maydell */ 249896fc80f5SPeter Maydell TCGv_i32 scalar; 249996fc80f5SPeter Maydell int pass; 250096fc80f5SPeter Maydell 250196fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 250296fc80f5SPeter Maydell return false; 250396fc80f5SPeter Maydell } 250496fc80f5SPeter Maydell 250596fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 250696fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 250796fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 250896fc80f5SPeter Maydell return false; 250996fc80f5SPeter Maydell } 251096fc80f5SPeter Maydell 251196fc80f5SPeter Maydell if (!opfn) { 251296fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 251396fc80f5SPeter Maydell return false; 251496fc80f5SPeter Maydell } 251596fc80f5SPeter Maydell 251696fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 251796fc80f5SPeter Maydell return false; 251896fc80f5SPeter Maydell } 251996fc80f5SPeter Maydell 252096fc80f5SPeter Maydell if (!vfp_access_check(s)) { 252196fc80f5SPeter Maydell return true; 252296fc80f5SPeter Maydell } 252396fc80f5SPeter Maydell 252496fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 252596fc80f5SPeter Maydell 252696fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 252796fc80f5SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, pass); 252896fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 252996fc80f5SPeter Maydell if (accfn) { 253096fc80f5SPeter Maydell TCGv_i32 rd = neon_load_reg(a->vd, pass); 253196fc80f5SPeter Maydell accfn(tmp, rd, tmp); 253296fc80f5SPeter Maydell tcg_temp_free_i32(rd); 253396fc80f5SPeter Maydell } 253496fc80f5SPeter Maydell neon_store_reg(a->vd, pass, tmp); 253596fc80f5SPeter Maydell } 253696fc80f5SPeter Maydell tcg_temp_free_i32(scalar); 253796fc80f5SPeter Maydell return true; 253896fc80f5SPeter Maydell } 253996fc80f5SPeter Maydell 254096fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 254196fc80f5SPeter Maydell { 254296fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 254396fc80f5SPeter Maydell NULL, 254496fc80f5SPeter Maydell gen_helper_neon_mul_u16, 254596fc80f5SPeter Maydell tcg_gen_mul_i32, 254696fc80f5SPeter Maydell NULL, 254796fc80f5SPeter Maydell }; 254896fc80f5SPeter Maydell 254996fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 255096fc80f5SPeter Maydell } 255196fc80f5SPeter Maydell 255296fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 255396fc80f5SPeter Maydell { 255496fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 255596fc80f5SPeter Maydell NULL, 255696fc80f5SPeter Maydell gen_helper_neon_mul_u16, 255796fc80f5SPeter Maydell tcg_gen_mul_i32, 255896fc80f5SPeter Maydell NULL, 255996fc80f5SPeter Maydell }; 256096fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 256196fc80f5SPeter Maydell NULL, 256296fc80f5SPeter Maydell gen_helper_neon_add_u16, 256396fc80f5SPeter Maydell tcg_gen_add_i32, 256496fc80f5SPeter Maydell NULL, 256596fc80f5SPeter Maydell }; 256696fc80f5SPeter Maydell 256796fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 256896fc80f5SPeter Maydell } 256996fc80f5SPeter Maydell 257096fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 257196fc80f5SPeter Maydell { 257296fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 257396fc80f5SPeter Maydell NULL, 257496fc80f5SPeter Maydell gen_helper_neon_mul_u16, 257596fc80f5SPeter Maydell tcg_gen_mul_i32, 257696fc80f5SPeter Maydell NULL, 257796fc80f5SPeter Maydell }; 257896fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 257996fc80f5SPeter Maydell NULL, 258096fc80f5SPeter Maydell gen_helper_neon_sub_u16, 258196fc80f5SPeter Maydell tcg_gen_sub_i32, 258296fc80f5SPeter Maydell NULL, 258396fc80f5SPeter Maydell }; 258496fc80f5SPeter Maydell 258596fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 258696fc80f5SPeter Maydell } 258785ac9aefSPeter Maydell 258885ac9aefSPeter Maydell /* 258985ac9aefSPeter Maydell * Rather than have a float-specific version of do_2scalar just for 259085ac9aefSPeter Maydell * three insns, we wrap a NeonGenTwoSingleOpFn to turn it into 259185ac9aefSPeter Maydell * a NeonGenTwoOpFn. 259285ac9aefSPeter Maydell */ 259385ac9aefSPeter Maydell #define WRAP_FP_FN(WRAPNAME, FUNC) \ 259485ac9aefSPeter Maydell static void WRAPNAME(TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \ 259585ac9aefSPeter Maydell { \ 2596a84d1d13SPeter Maydell TCGv_ptr fpstatus = fpstatus_ptr(FPST_STD); \ 259785ac9aefSPeter Maydell FUNC(rd, rn, rm, fpstatus); \ 259885ac9aefSPeter Maydell tcg_temp_free_ptr(fpstatus); \ 259985ac9aefSPeter Maydell } 260085ac9aefSPeter Maydell 260185ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls) 260285ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds) 260385ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs) 260485ac9aefSPeter Maydell 260585ac9aefSPeter Maydell static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a) 260685ac9aefSPeter Maydell { 260785ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 260885ac9aefSPeter Maydell NULL, 260985ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 261085ac9aefSPeter Maydell gen_VMUL_F_mul, 261185ac9aefSPeter Maydell NULL, 261285ac9aefSPeter Maydell }; 261385ac9aefSPeter Maydell 261485ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 261585ac9aefSPeter Maydell } 261685ac9aefSPeter Maydell 261785ac9aefSPeter Maydell static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a) 261885ac9aefSPeter Maydell { 261985ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 262085ac9aefSPeter Maydell NULL, 262185ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 262285ac9aefSPeter Maydell gen_VMUL_F_mul, 262385ac9aefSPeter Maydell NULL, 262485ac9aefSPeter Maydell }; 262585ac9aefSPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 262685ac9aefSPeter Maydell NULL, 262785ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 262885ac9aefSPeter Maydell gen_VMUL_F_add, 262985ac9aefSPeter Maydell NULL, 263085ac9aefSPeter Maydell }; 263185ac9aefSPeter Maydell 263285ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 263385ac9aefSPeter Maydell } 263485ac9aefSPeter Maydell 263585ac9aefSPeter Maydell static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a) 263685ac9aefSPeter Maydell { 263785ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 263885ac9aefSPeter Maydell NULL, 263985ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 264085ac9aefSPeter Maydell gen_VMUL_F_mul, 264185ac9aefSPeter Maydell NULL, 264285ac9aefSPeter Maydell }; 264385ac9aefSPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 264485ac9aefSPeter Maydell NULL, 264585ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 264685ac9aefSPeter Maydell gen_VMUL_F_sub, 264785ac9aefSPeter Maydell NULL, 264885ac9aefSPeter Maydell }; 264985ac9aefSPeter Maydell 265085ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 265185ac9aefSPeter Maydell } 2652b2fc7be9SPeter Maydell 2653b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2654b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2655b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2656b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2657b2fc7be9SPeter Maydell 2658b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2659b2fc7be9SPeter Maydell { 2660b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2661b2fc7be9SPeter Maydell NULL, 2662b2fc7be9SPeter Maydell gen_VQDMULH_16, 2663b2fc7be9SPeter Maydell gen_VQDMULH_32, 2664b2fc7be9SPeter Maydell NULL, 2665b2fc7be9SPeter Maydell }; 2666b2fc7be9SPeter Maydell 2667b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2668b2fc7be9SPeter Maydell } 2669b2fc7be9SPeter Maydell 2670b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2671b2fc7be9SPeter Maydell { 2672b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2673b2fc7be9SPeter Maydell NULL, 2674b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2675b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2676b2fc7be9SPeter Maydell NULL, 2677b2fc7be9SPeter Maydell }; 2678b2fc7be9SPeter Maydell 2679b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2680b2fc7be9SPeter Maydell } 2681aa318f5bSPeter Maydell 2682aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2683aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2684aa318f5bSPeter Maydell { 2685aa318f5bSPeter Maydell /* 2686aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2687aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2688aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2689aa318f5bSPeter Maydell */ 2690aa318f5bSPeter Maydell TCGv_i32 scalar; 2691aa318f5bSPeter Maydell int pass; 2692aa318f5bSPeter Maydell 2693aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2694aa318f5bSPeter Maydell return false; 2695aa318f5bSPeter Maydell } 2696aa318f5bSPeter Maydell 2697aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2698aa318f5bSPeter Maydell return false; 2699aa318f5bSPeter Maydell } 2700aa318f5bSPeter Maydell 2701aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2702aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2703aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2704aa318f5bSPeter Maydell return false; 2705aa318f5bSPeter Maydell } 2706aa318f5bSPeter Maydell 2707aa318f5bSPeter Maydell if (!opfn) { 2708aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2709aa318f5bSPeter Maydell return false; 2710aa318f5bSPeter Maydell } 2711aa318f5bSPeter Maydell 2712aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2713aa318f5bSPeter Maydell return false; 2714aa318f5bSPeter Maydell } 2715aa318f5bSPeter Maydell 2716aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2717aa318f5bSPeter Maydell return true; 2718aa318f5bSPeter Maydell } 2719aa318f5bSPeter Maydell 2720aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2721aa318f5bSPeter Maydell 2722aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2723aa318f5bSPeter Maydell TCGv_i32 rn = neon_load_reg(a->vn, pass); 2724aa318f5bSPeter Maydell TCGv_i32 rd = neon_load_reg(a->vd, pass); 2725aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2726aa318f5bSPeter Maydell tcg_temp_free_i32(rn); 2727aa318f5bSPeter Maydell neon_store_reg(a->vd, pass, rd); 2728aa318f5bSPeter Maydell } 2729aa318f5bSPeter Maydell tcg_temp_free_i32(scalar); 2730aa318f5bSPeter Maydell 2731aa318f5bSPeter Maydell return true; 2732aa318f5bSPeter Maydell } 2733aa318f5bSPeter Maydell 2734aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2735aa318f5bSPeter Maydell { 2736aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2737aa318f5bSPeter Maydell NULL, 2738aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2739aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2740aa318f5bSPeter Maydell NULL, 2741aa318f5bSPeter Maydell }; 2742aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2743aa318f5bSPeter Maydell } 2744aa318f5bSPeter Maydell 2745aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2746aa318f5bSPeter Maydell { 2747aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2748aa318f5bSPeter Maydell NULL, 2749aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2750aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2751aa318f5bSPeter Maydell NULL, 2752aa318f5bSPeter Maydell }; 2753aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2754aa318f5bSPeter Maydell } 275577e576a9SPeter Maydell 275677e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 275777e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 275877e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 275977e576a9SPeter Maydell { 276077e576a9SPeter Maydell /* 276177e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 276277e576a9SPeter Maydell * operation on the input elements and the scalar which produces 276377e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 276477e576a9SPeter Maydell * operation of that result into the destination. 276577e576a9SPeter Maydell */ 276677e576a9SPeter Maydell TCGv_i32 scalar, rn; 276777e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 276877e576a9SPeter Maydell 276977e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 277077e576a9SPeter Maydell return false; 277177e576a9SPeter Maydell } 277277e576a9SPeter Maydell 277377e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 277477e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 277577e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 277677e576a9SPeter Maydell return false; 277777e576a9SPeter Maydell } 277877e576a9SPeter Maydell 277977e576a9SPeter Maydell if (!opfn) { 278077e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 278177e576a9SPeter Maydell return false; 278277e576a9SPeter Maydell } 278377e576a9SPeter Maydell 278477e576a9SPeter Maydell if (a->vd & 1) { 278577e576a9SPeter Maydell return false; 278677e576a9SPeter Maydell } 278777e576a9SPeter Maydell 278877e576a9SPeter Maydell if (!vfp_access_check(s)) { 278977e576a9SPeter Maydell return true; 279077e576a9SPeter Maydell } 279177e576a9SPeter Maydell 279277e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 279377e576a9SPeter Maydell 279477e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 279577e576a9SPeter Maydell rn = neon_load_reg(a->vn, 0); 279677e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 279777e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 279877e576a9SPeter Maydell tcg_temp_free_i32(rn); 279977e576a9SPeter Maydell 280077e576a9SPeter Maydell rn = neon_load_reg(a->vn, 1); 280177e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 280277e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 280377e576a9SPeter Maydell tcg_temp_free_i32(rn); 280477e576a9SPeter Maydell tcg_temp_free_i32(scalar); 280577e576a9SPeter Maydell 280677e576a9SPeter Maydell if (accfn) { 280777e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 280877e576a9SPeter Maydell neon_load_reg64(t64, a->vd); 280977e576a9SPeter Maydell accfn(t64, t64, rn0_64); 281077e576a9SPeter Maydell neon_store_reg64(t64, a->vd); 281177e576a9SPeter Maydell neon_load_reg64(t64, a->vd + 1); 281277e576a9SPeter Maydell accfn(t64, t64, rn1_64); 281377e576a9SPeter Maydell neon_store_reg64(t64, a->vd + 1); 281477e576a9SPeter Maydell tcg_temp_free_i64(t64); 281577e576a9SPeter Maydell } else { 281677e576a9SPeter Maydell neon_store_reg64(rn0_64, a->vd); 281777e576a9SPeter Maydell neon_store_reg64(rn1_64, a->vd + 1); 281877e576a9SPeter Maydell } 281977e576a9SPeter Maydell tcg_temp_free_i64(rn0_64); 282077e576a9SPeter Maydell tcg_temp_free_i64(rn1_64); 282177e576a9SPeter Maydell return true; 282277e576a9SPeter Maydell } 282377e576a9SPeter Maydell 282477e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 282577e576a9SPeter Maydell { 282677e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 282777e576a9SPeter Maydell NULL, 282877e576a9SPeter Maydell gen_helper_neon_mull_s16, 282977e576a9SPeter Maydell gen_mull_s32, 283077e576a9SPeter Maydell NULL, 283177e576a9SPeter Maydell }; 283277e576a9SPeter Maydell 283377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 283477e576a9SPeter Maydell } 283577e576a9SPeter Maydell 283677e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 283777e576a9SPeter Maydell { 283877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 283977e576a9SPeter Maydell NULL, 284077e576a9SPeter Maydell gen_helper_neon_mull_u16, 284177e576a9SPeter Maydell gen_mull_u32, 284277e576a9SPeter Maydell NULL, 284377e576a9SPeter Maydell }; 284477e576a9SPeter Maydell 284577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 284677e576a9SPeter Maydell } 284777e576a9SPeter Maydell 284877e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 284977e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 285077e576a9SPeter Maydell { \ 285177e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 285277e576a9SPeter Maydell NULL, \ 285377e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 285477e576a9SPeter Maydell gen_##MULL##32, \ 285577e576a9SPeter Maydell NULL, \ 285677e576a9SPeter Maydell }; \ 285777e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 285877e576a9SPeter Maydell NULL, \ 285977e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 286077e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 286177e576a9SPeter Maydell NULL, \ 286277e576a9SPeter Maydell }; \ 286377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 286477e576a9SPeter Maydell } 286577e576a9SPeter Maydell 286677e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 286777e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 286877e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 286977e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 287077e576a9SPeter Maydell 287177e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 287277e576a9SPeter Maydell { 287377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 287477e576a9SPeter Maydell NULL, 287577e576a9SPeter Maydell gen_VQDMULL_16, 287677e576a9SPeter Maydell gen_VQDMULL_32, 287777e576a9SPeter Maydell NULL, 287877e576a9SPeter Maydell }; 287977e576a9SPeter Maydell 288077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 288177e576a9SPeter Maydell } 288277e576a9SPeter Maydell 288377e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 288477e576a9SPeter Maydell { 288577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 288677e576a9SPeter Maydell NULL, 288777e576a9SPeter Maydell gen_VQDMULL_16, 288877e576a9SPeter Maydell gen_VQDMULL_32, 288977e576a9SPeter Maydell NULL, 289077e576a9SPeter Maydell }; 289177e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 289277e576a9SPeter Maydell NULL, 289377e576a9SPeter Maydell gen_VQDMLAL_acc_16, 289477e576a9SPeter Maydell gen_VQDMLAL_acc_32, 289577e576a9SPeter Maydell NULL, 289677e576a9SPeter Maydell }; 289777e576a9SPeter Maydell 289877e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 289977e576a9SPeter Maydell } 290077e576a9SPeter Maydell 290177e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 290277e576a9SPeter Maydell { 290377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 290477e576a9SPeter Maydell NULL, 290577e576a9SPeter Maydell gen_VQDMULL_16, 290677e576a9SPeter Maydell gen_VQDMULL_32, 290777e576a9SPeter Maydell NULL, 290877e576a9SPeter Maydell }; 290977e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 291077e576a9SPeter Maydell NULL, 291177e576a9SPeter Maydell gen_VQDMLSL_acc_16, 291277e576a9SPeter Maydell gen_VQDMLSL_acc_32, 291377e576a9SPeter Maydell NULL, 291477e576a9SPeter Maydell }; 291577e576a9SPeter Maydell 291677e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 291777e576a9SPeter Maydell } 29180aad761fSPeter Maydell 29190aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 29200aad761fSPeter Maydell { 29210aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 29220aad761fSPeter Maydell return false; 29230aad761fSPeter Maydell } 29240aad761fSPeter Maydell 29250aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 29260aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 29270aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 29280aad761fSPeter Maydell return false; 29290aad761fSPeter Maydell } 29300aad761fSPeter Maydell 29310aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 29320aad761fSPeter Maydell return false; 29330aad761fSPeter Maydell } 29340aad761fSPeter Maydell 29350aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 29360aad761fSPeter Maydell return false; 29370aad761fSPeter Maydell } 29380aad761fSPeter Maydell 29390aad761fSPeter Maydell if (!vfp_access_check(s)) { 29400aad761fSPeter Maydell return true; 29410aad761fSPeter Maydell } 29420aad761fSPeter Maydell 29430aad761fSPeter Maydell if (!a->q) { 29440aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 29450aad761fSPeter Maydell TCGv_i64 left, right, dest; 29460aad761fSPeter Maydell 29470aad761fSPeter Maydell left = tcg_temp_new_i64(); 29480aad761fSPeter Maydell right = tcg_temp_new_i64(); 29490aad761fSPeter Maydell dest = tcg_temp_new_i64(); 29500aad761fSPeter Maydell 29510aad761fSPeter Maydell neon_load_reg64(right, a->vn); 29520aad761fSPeter Maydell neon_load_reg64(left, a->vm); 29530aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 29540aad761fSPeter Maydell neon_store_reg64(dest, a->vd); 29550aad761fSPeter Maydell 29560aad761fSPeter Maydell tcg_temp_free_i64(left); 29570aad761fSPeter Maydell tcg_temp_free_i64(right); 29580aad761fSPeter Maydell tcg_temp_free_i64(dest); 29590aad761fSPeter Maydell } else { 29600aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 29610aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 29620aad761fSPeter Maydell 29630aad761fSPeter Maydell left = tcg_temp_new_i64(); 29640aad761fSPeter Maydell middle = tcg_temp_new_i64(); 29650aad761fSPeter Maydell right = tcg_temp_new_i64(); 29660aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 29670aad761fSPeter Maydell destright = tcg_temp_new_i64(); 29680aad761fSPeter Maydell 29690aad761fSPeter Maydell if (a->imm < 8) { 29700aad761fSPeter Maydell neon_load_reg64(right, a->vn); 29710aad761fSPeter Maydell neon_load_reg64(middle, a->vn + 1); 29720aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 29730aad761fSPeter Maydell neon_load_reg64(left, a->vm); 29740aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 29750aad761fSPeter Maydell } else { 29760aad761fSPeter Maydell neon_load_reg64(right, a->vn + 1); 29770aad761fSPeter Maydell neon_load_reg64(middle, a->vm); 29780aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 29790aad761fSPeter Maydell neon_load_reg64(left, a->vm + 1); 29800aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 29810aad761fSPeter Maydell } 29820aad761fSPeter Maydell 29830aad761fSPeter Maydell neon_store_reg64(destright, a->vd); 29840aad761fSPeter Maydell neon_store_reg64(destleft, a->vd + 1); 29850aad761fSPeter Maydell 29860aad761fSPeter Maydell tcg_temp_free_i64(destright); 29870aad761fSPeter Maydell tcg_temp_free_i64(destleft); 29880aad761fSPeter Maydell tcg_temp_free_i64(right); 29890aad761fSPeter Maydell tcg_temp_free_i64(middle); 29900aad761fSPeter Maydell tcg_temp_free_i64(left); 29910aad761fSPeter Maydell } 29920aad761fSPeter Maydell return true; 29930aad761fSPeter Maydell } 299454e96c74SPeter Maydell 299554e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 299654e96c74SPeter Maydell { 299754e96c74SPeter Maydell int n; 299854e96c74SPeter Maydell TCGv_i32 tmp, tmp2, tmp3, tmp4; 299954e96c74SPeter Maydell TCGv_ptr ptr1; 300054e96c74SPeter Maydell 300154e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 300254e96c74SPeter Maydell return false; 300354e96c74SPeter Maydell } 300454e96c74SPeter Maydell 300554e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 300654e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 300754e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 300854e96c74SPeter Maydell return false; 300954e96c74SPeter Maydell } 301054e96c74SPeter Maydell 301154e96c74SPeter Maydell if (!vfp_access_check(s)) { 301254e96c74SPeter Maydell return true; 301354e96c74SPeter Maydell } 301454e96c74SPeter Maydell 301554e96c74SPeter Maydell n = a->len + 1; 301654e96c74SPeter Maydell if ((a->vn + n) > 32) { 301754e96c74SPeter Maydell /* 301854e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 301954e96c74SPeter Maydell * helper function running off the end of the register file. 302054e96c74SPeter Maydell */ 302154e96c74SPeter Maydell return false; 302254e96c74SPeter Maydell } 302354e96c74SPeter Maydell n <<= 3; 302454e96c74SPeter Maydell if (a->op) { 302554e96c74SPeter Maydell tmp = neon_load_reg(a->vd, 0); 302654e96c74SPeter Maydell } else { 302754e96c74SPeter Maydell tmp = tcg_temp_new_i32(); 302854e96c74SPeter Maydell tcg_gen_movi_i32(tmp, 0); 302954e96c74SPeter Maydell } 303054e96c74SPeter Maydell tmp2 = neon_load_reg(a->vm, 0); 303154e96c74SPeter Maydell ptr1 = vfp_reg_ptr(true, a->vn); 303254e96c74SPeter Maydell tmp4 = tcg_const_i32(n); 303354e96c74SPeter Maydell gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4); 303454e96c74SPeter Maydell tcg_temp_free_i32(tmp); 303554e96c74SPeter Maydell if (a->op) { 303654e96c74SPeter Maydell tmp = neon_load_reg(a->vd, 1); 303754e96c74SPeter Maydell } else { 303854e96c74SPeter Maydell tmp = tcg_temp_new_i32(); 303954e96c74SPeter Maydell tcg_gen_movi_i32(tmp, 0); 304054e96c74SPeter Maydell } 304154e96c74SPeter Maydell tmp3 = neon_load_reg(a->vm, 1); 304254e96c74SPeter Maydell gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4); 304354e96c74SPeter Maydell tcg_temp_free_i32(tmp4); 304454e96c74SPeter Maydell tcg_temp_free_ptr(ptr1); 304554e96c74SPeter Maydell neon_store_reg(a->vd, 0, tmp2); 304654e96c74SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 304754e96c74SPeter Maydell tcg_temp_free_i32(tmp); 304854e96c74SPeter Maydell return true; 304954e96c74SPeter Maydell } 30509aaa23c2SPeter Maydell 30519aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 30529aaa23c2SPeter Maydell { 30539aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30549aaa23c2SPeter Maydell return false; 30559aaa23c2SPeter Maydell } 30569aaa23c2SPeter Maydell 30579aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 30589aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 30599aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 30609aaa23c2SPeter Maydell return false; 30619aaa23c2SPeter Maydell } 30629aaa23c2SPeter Maydell 30639aaa23c2SPeter Maydell if (a->vd & a->q) { 30649aaa23c2SPeter Maydell return false; 30659aaa23c2SPeter Maydell } 30669aaa23c2SPeter Maydell 30679aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 30689aaa23c2SPeter Maydell return true; 30699aaa23c2SPeter Maydell } 30709aaa23c2SPeter Maydell 30719aaa23c2SPeter Maydell tcg_gen_gvec_dup_mem(a->size, neon_reg_offset(a->vd, 0), 30729aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 30739aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 30749aaa23c2SPeter Maydell return true; 30759aaa23c2SPeter Maydell } 3076353d2b85SPeter Maydell 3077353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 3078353d2b85SPeter Maydell { 3079353d2b85SPeter Maydell int pass, half; 3080353d2b85SPeter Maydell 3081353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3082353d2b85SPeter Maydell return false; 3083353d2b85SPeter Maydell } 3084353d2b85SPeter Maydell 3085353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3086353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3087353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3088353d2b85SPeter Maydell return false; 3089353d2b85SPeter Maydell } 3090353d2b85SPeter Maydell 3091353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 3092353d2b85SPeter Maydell return false; 3093353d2b85SPeter Maydell } 3094353d2b85SPeter Maydell 3095353d2b85SPeter Maydell if (a->size == 3) { 3096353d2b85SPeter Maydell return false; 3097353d2b85SPeter Maydell } 3098353d2b85SPeter Maydell 3099353d2b85SPeter Maydell if (!vfp_access_check(s)) { 3100353d2b85SPeter Maydell return true; 3101353d2b85SPeter Maydell } 3102353d2b85SPeter Maydell 3103353d2b85SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 3104353d2b85SPeter Maydell TCGv_i32 tmp[2]; 3105353d2b85SPeter Maydell 3106353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 3107353d2b85SPeter Maydell tmp[half] = neon_load_reg(a->vm, pass * 2 + half); 3108353d2b85SPeter Maydell switch (a->size) { 3109353d2b85SPeter Maydell case 0: 3110353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 3111353d2b85SPeter Maydell break; 3112353d2b85SPeter Maydell case 1: 31138ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 3114353d2b85SPeter Maydell break; 3115353d2b85SPeter Maydell case 2: 3116353d2b85SPeter Maydell break; 3117353d2b85SPeter Maydell default: 3118353d2b85SPeter Maydell g_assert_not_reached(); 3119353d2b85SPeter Maydell } 3120353d2b85SPeter Maydell } 3121353d2b85SPeter Maydell neon_store_reg(a->vd, pass * 2, tmp[1]); 3122353d2b85SPeter Maydell neon_store_reg(a->vd, pass * 2 + 1, tmp[0]); 3123353d2b85SPeter Maydell } 3124353d2b85SPeter Maydell return true; 3125353d2b85SPeter Maydell } 31266106af3aSPeter Maydell 31276106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 31286106af3aSPeter Maydell NeonGenWidenFn *widenfn, 31296106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 31306106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 31316106af3aSPeter Maydell { 31326106af3aSPeter Maydell /* 31336106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 31346106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 31356106af3aSPeter Maydell * into the destination with the accfn. 31366106af3aSPeter Maydell */ 31376106af3aSPeter Maydell int pass; 31386106af3aSPeter Maydell 31396106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 31406106af3aSPeter Maydell return false; 31416106af3aSPeter Maydell } 31426106af3aSPeter Maydell 31436106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 31446106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 31456106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 31466106af3aSPeter Maydell return false; 31476106af3aSPeter Maydell } 31486106af3aSPeter Maydell 31496106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 31506106af3aSPeter Maydell return false; 31516106af3aSPeter Maydell } 31526106af3aSPeter Maydell 31536106af3aSPeter Maydell if (!widenfn) { 31546106af3aSPeter Maydell return false; 31556106af3aSPeter Maydell } 31566106af3aSPeter Maydell 31576106af3aSPeter Maydell if (!vfp_access_check(s)) { 31586106af3aSPeter Maydell return true; 31596106af3aSPeter Maydell } 31606106af3aSPeter Maydell 31616106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 31626106af3aSPeter Maydell TCGv_i32 tmp; 31636106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 31646106af3aSPeter Maydell 31656106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 31666106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 31676106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 31686106af3aSPeter Maydell tmp = neon_load_reg(a->vm, pass * 2); 31696106af3aSPeter Maydell widenfn(rm0_64, tmp); 31706106af3aSPeter Maydell tcg_temp_free_i32(tmp); 31716106af3aSPeter Maydell tmp = neon_load_reg(a->vm, pass * 2 + 1); 31726106af3aSPeter Maydell widenfn(rm1_64, tmp); 31736106af3aSPeter Maydell tcg_temp_free_i32(tmp); 31746106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 31756106af3aSPeter Maydell tcg_temp_free_i64(rm0_64); 31766106af3aSPeter Maydell tcg_temp_free_i64(rm1_64); 31776106af3aSPeter Maydell 31786106af3aSPeter Maydell if (accfn) { 31796106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 31806106af3aSPeter Maydell neon_load_reg64(tmp64, a->vd + pass); 31816106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 31826106af3aSPeter Maydell tcg_temp_free_i64(tmp64); 31836106af3aSPeter Maydell } 31846106af3aSPeter Maydell neon_store_reg64(rd_64, a->vd + pass); 31856106af3aSPeter Maydell tcg_temp_free_i64(rd_64); 31866106af3aSPeter Maydell } 31876106af3aSPeter Maydell return true; 31886106af3aSPeter Maydell } 31896106af3aSPeter Maydell 31906106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 31916106af3aSPeter Maydell { 31926106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31936106af3aSPeter Maydell gen_helper_neon_widen_s8, 31946106af3aSPeter Maydell gen_helper_neon_widen_s16, 31956106af3aSPeter Maydell tcg_gen_ext_i32_i64, 31966106af3aSPeter Maydell NULL, 31976106af3aSPeter Maydell }; 31986106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31996106af3aSPeter Maydell gen_helper_neon_paddl_u16, 32006106af3aSPeter Maydell gen_helper_neon_paddl_u32, 32016106af3aSPeter Maydell tcg_gen_add_i64, 32026106af3aSPeter Maydell NULL, 32036106af3aSPeter Maydell }; 32046106af3aSPeter Maydell 32056106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 32066106af3aSPeter Maydell } 32076106af3aSPeter Maydell 32086106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 32096106af3aSPeter Maydell { 32106106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 32116106af3aSPeter Maydell gen_helper_neon_widen_u8, 32126106af3aSPeter Maydell gen_helper_neon_widen_u16, 32136106af3aSPeter Maydell tcg_gen_extu_i32_i64, 32146106af3aSPeter Maydell NULL, 32156106af3aSPeter Maydell }; 32166106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 32176106af3aSPeter Maydell gen_helper_neon_paddl_u16, 32186106af3aSPeter Maydell gen_helper_neon_paddl_u32, 32196106af3aSPeter Maydell tcg_gen_add_i64, 32206106af3aSPeter Maydell NULL, 32216106af3aSPeter Maydell }; 32226106af3aSPeter Maydell 32236106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 32246106af3aSPeter Maydell } 32256106af3aSPeter Maydell 32266106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 32276106af3aSPeter Maydell { 32286106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 32296106af3aSPeter Maydell gen_helper_neon_widen_s8, 32306106af3aSPeter Maydell gen_helper_neon_widen_s16, 32316106af3aSPeter Maydell tcg_gen_ext_i32_i64, 32326106af3aSPeter Maydell NULL, 32336106af3aSPeter Maydell }; 32346106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 32356106af3aSPeter Maydell gen_helper_neon_paddl_u16, 32366106af3aSPeter Maydell gen_helper_neon_paddl_u32, 32376106af3aSPeter Maydell tcg_gen_add_i64, 32386106af3aSPeter Maydell NULL, 32396106af3aSPeter Maydell }; 32406106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 32416106af3aSPeter Maydell gen_helper_neon_addl_u16, 32426106af3aSPeter Maydell gen_helper_neon_addl_u32, 32436106af3aSPeter Maydell tcg_gen_add_i64, 32446106af3aSPeter Maydell NULL, 32456106af3aSPeter Maydell }; 32466106af3aSPeter Maydell 32476106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 32486106af3aSPeter Maydell accfn[a->size]); 32496106af3aSPeter Maydell } 32506106af3aSPeter Maydell 32516106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 32526106af3aSPeter Maydell { 32536106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 32546106af3aSPeter Maydell gen_helper_neon_widen_u8, 32556106af3aSPeter Maydell gen_helper_neon_widen_u16, 32566106af3aSPeter Maydell tcg_gen_extu_i32_i64, 32576106af3aSPeter Maydell NULL, 32586106af3aSPeter Maydell }; 32596106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 32606106af3aSPeter Maydell gen_helper_neon_paddl_u16, 32616106af3aSPeter Maydell gen_helper_neon_paddl_u32, 32626106af3aSPeter Maydell tcg_gen_add_i64, 32636106af3aSPeter Maydell NULL, 32646106af3aSPeter Maydell }; 32656106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 32666106af3aSPeter Maydell gen_helper_neon_addl_u16, 32676106af3aSPeter Maydell gen_helper_neon_addl_u32, 32686106af3aSPeter Maydell tcg_gen_add_i64, 32696106af3aSPeter Maydell NULL, 32706106af3aSPeter Maydell }; 32716106af3aSPeter Maydell 32726106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 32736106af3aSPeter Maydell accfn[a->size]); 32746106af3aSPeter Maydell } 3275567663a2SPeter Maydell 3276567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3277567663a2SPeter Maydell 3278567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3279567663a2SPeter Maydell ZipFn *fn) 3280567663a2SPeter Maydell { 3281567663a2SPeter Maydell TCGv_ptr pd, pm; 3282567663a2SPeter Maydell 3283567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3284567663a2SPeter Maydell return false; 3285567663a2SPeter Maydell } 3286567663a2SPeter Maydell 3287567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3288567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3289567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3290567663a2SPeter Maydell return false; 3291567663a2SPeter Maydell } 3292567663a2SPeter Maydell 3293567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3294567663a2SPeter Maydell return false; 3295567663a2SPeter Maydell } 3296567663a2SPeter Maydell 3297567663a2SPeter Maydell if (!fn) { 3298567663a2SPeter Maydell /* Bad size or size/q combination */ 3299567663a2SPeter Maydell return false; 3300567663a2SPeter Maydell } 3301567663a2SPeter Maydell 3302567663a2SPeter Maydell if (!vfp_access_check(s)) { 3303567663a2SPeter Maydell return true; 3304567663a2SPeter Maydell } 3305567663a2SPeter Maydell 3306567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3307567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3308567663a2SPeter Maydell fn(pd, pm); 3309567663a2SPeter Maydell tcg_temp_free_ptr(pd); 3310567663a2SPeter Maydell tcg_temp_free_ptr(pm); 3311567663a2SPeter Maydell return true; 3312567663a2SPeter Maydell } 3313567663a2SPeter Maydell 3314567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3315567663a2SPeter Maydell { 3316567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3317567663a2SPeter Maydell { 3318567663a2SPeter Maydell gen_helper_neon_unzip8, 3319567663a2SPeter Maydell gen_helper_neon_unzip16, 3320567663a2SPeter Maydell NULL, 3321567663a2SPeter Maydell NULL, 3322567663a2SPeter Maydell }, { 3323567663a2SPeter Maydell gen_helper_neon_qunzip8, 3324567663a2SPeter Maydell gen_helper_neon_qunzip16, 3325567663a2SPeter Maydell gen_helper_neon_qunzip32, 3326567663a2SPeter Maydell NULL, 3327567663a2SPeter Maydell } 3328567663a2SPeter Maydell }; 3329567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3330567663a2SPeter Maydell } 3331567663a2SPeter Maydell 3332567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3333567663a2SPeter Maydell { 3334567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3335567663a2SPeter Maydell { 3336567663a2SPeter Maydell gen_helper_neon_zip8, 3337567663a2SPeter Maydell gen_helper_neon_zip16, 3338567663a2SPeter Maydell NULL, 3339567663a2SPeter Maydell NULL, 3340567663a2SPeter Maydell }, { 3341567663a2SPeter Maydell gen_helper_neon_qzip8, 3342567663a2SPeter Maydell gen_helper_neon_qzip16, 3343567663a2SPeter Maydell gen_helper_neon_qzip32, 3344567663a2SPeter Maydell NULL, 3345567663a2SPeter Maydell } 3346567663a2SPeter Maydell }; 3347567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3348567663a2SPeter Maydell } 33493882bdacSPeter Maydell 33503882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 33513882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 33523882bdacSPeter Maydell { 33533882bdacSPeter Maydell TCGv_i64 rm; 33543882bdacSPeter Maydell TCGv_i32 rd0, rd1; 33553882bdacSPeter Maydell 33563882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 33573882bdacSPeter Maydell return false; 33583882bdacSPeter Maydell } 33593882bdacSPeter Maydell 33603882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 33613882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 33623882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 33633882bdacSPeter Maydell return false; 33643882bdacSPeter Maydell } 33653882bdacSPeter Maydell 33663882bdacSPeter Maydell if (a->vm & 1) { 33673882bdacSPeter Maydell return false; 33683882bdacSPeter Maydell } 33693882bdacSPeter Maydell 33703882bdacSPeter Maydell if (!narrowfn) { 33713882bdacSPeter Maydell return false; 33723882bdacSPeter Maydell } 33733882bdacSPeter Maydell 33743882bdacSPeter Maydell if (!vfp_access_check(s)) { 33753882bdacSPeter Maydell return true; 33763882bdacSPeter Maydell } 33773882bdacSPeter Maydell 33783882bdacSPeter Maydell rm = tcg_temp_new_i64(); 33793882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 33803882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 33813882bdacSPeter Maydell 33823882bdacSPeter Maydell neon_load_reg64(rm, a->vm); 33833882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 33843882bdacSPeter Maydell neon_load_reg64(rm, a->vm + 1); 33853882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 33863882bdacSPeter Maydell neon_store_reg(a->vd, 0, rd0); 33873882bdacSPeter Maydell neon_store_reg(a->vd, 1, rd1); 33883882bdacSPeter Maydell tcg_temp_free_i64(rm); 33893882bdacSPeter Maydell return true; 33903882bdacSPeter Maydell } 33913882bdacSPeter Maydell 33923882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 33933882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 33943882bdacSPeter Maydell { \ 33953882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 33963882bdacSPeter Maydell FUNC##8, \ 33973882bdacSPeter Maydell FUNC##16, \ 33983882bdacSPeter Maydell FUNC##32, \ 33993882bdacSPeter Maydell NULL, \ 34003882bdacSPeter Maydell }; \ 34013882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 34023882bdacSPeter Maydell } 34033882bdacSPeter Maydell 34043882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 34053882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 34063882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 34073882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3408749e2be3SPeter Maydell 3409749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3410749e2be3SPeter Maydell { 3411749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3412749e2be3SPeter Maydell TCGv_i64 rd; 3413749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3414749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3415749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3416749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3417749e2be3SPeter Maydell NULL, 3418749e2be3SPeter Maydell }; 3419749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3420749e2be3SPeter Maydell 3421749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3422749e2be3SPeter Maydell return false; 3423749e2be3SPeter Maydell } 3424749e2be3SPeter Maydell 3425749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3426749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3427749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3428749e2be3SPeter Maydell return false; 3429749e2be3SPeter Maydell } 3430749e2be3SPeter Maydell 3431749e2be3SPeter Maydell if (a->vd & 1) { 3432749e2be3SPeter Maydell return false; 3433749e2be3SPeter Maydell } 3434749e2be3SPeter Maydell 3435749e2be3SPeter Maydell if (!widenfn) { 3436749e2be3SPeter Maydell return false; 3437749e2be3SPeter Maydell } 3438749e2be3SPeter Maydell 3439749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3440749e2be3SPeter Maydell return true; 3441749e2be3SPeter Maydell } 3442749e2be3SPeter Maydell 3443749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3444749e2be3SPeter Maydell 3445749e2be3SPeter Maydell rm0 = neon_load_reg(a->vm, 0); 3446749e2be3SPeter Maydell rm1 = neon_load_reg(a->vm, 1); 3447749e2be3SPeter Maydell 3448749e2be3SPeter Maydell widenfn(rd, rm0); 3449749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 3450749e2be3SPeter Maydell neon_store_reg64(rd, a->vd); 3451749e2be3SPeter Maydell widenfn(rd, rm1); 3452749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 3453749e2be3SPeter Maydell neon_store_reg64(rd, a->vd + 1); 3454749e2be3SPeter Maydell 3455749e2be3SPeter Maydell tcg_temp_free_i64(rd); 3456749e2be3SPeter Maydell tcg_temp_free_i32(rm0); 3457749e2be3SPeter Maydell tcg_temp_free_i32(rm1); 3458749e2be3SPeter Maydell return true; 3459749e2be3SPeter Maydell } 3460654a5173SPeter Maydell 3461654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3462654a5173SPeter Maydell { 3463654a5173SPeter Maydell TCGv_ptr fpst; 3464654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3465654a5173SPeter Maydell 3466654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3467654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3468654a5173SPeter Maydell return false; 3469654a5173SPeter Maydell } 3470654a5173SPeter Maydell 3471654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3472654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3473654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3474654a5173SPeter Maydell return false; 3475654a5173SPeter Maydell } 3476654a5173SPeter Maydell 3477654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3478654a5173SPeter Maydell return false; 3479654a5173SPeter Maydell } 3480654a5173SPeter Maydell 3481654a5173SPeter Maydell if (!vfp_access_check(s)) { 3482654a5173SPeter Maydell return true; 3483654a5173SPeter Maydell } 3484654a5173SPeter Maydell 3485a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3486654a5173SPeter Maydell ahp = get_ahp_flag(); 3487654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 0); 3488654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3489654a5173SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 3490654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3491654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3492654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3493654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3494654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 2); 3495654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3496654a5173SPeter Maydell tmp3 = neon_load_reg(a->vm, 3); 3497654a5173SPeter Maydell neon_store_reg(a->vd, 0, tmp2); 3498654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3499654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3500654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3501654a5173SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 3502654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3503654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3504654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3505654a5173SPeter Maydell 3506654a5173SPeter Maydell return true; 3507654a5173SPeter Maydell } 3508654a5173SPeter Maydell 3509654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3510654a5173SPeter Maydell { 3511654a5173SPeter Maydell TCGv_ptr fpst; 3512654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3513654a5173SPeter Maydell 3514654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3515654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3516654a5173SPeter Maydell return false; 3517654a5173SPeter Maydell } 3518654a5173SPeter Maydell 3519654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3520654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3521654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3522654a5173SPeter Maydell return false; 3523654a5173SPeter Maydell } 3524654a5173SPeter Maydell 3525654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3526654a5173SPeter Maydell return false; 3527654a5173SPeter Maydell } 3528654a5173SPeter Maydell 3529654a5173SPeter Maydell if (!vfp_access_check(s)) { 3530654a5173SPeter Maydell return true; 3531654a5173SPeter Maydell } 3532654a5173SPeter Maydell 3533a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3534654a5173SPeter Maydell ahp = get_ahp_flag(); 3535654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3536654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 0); 3537654a5173SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 3538654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3539654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3540654a5173SPeter Maydell neon_store_reg(a->vd, 0, tmp3); 3541654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3542654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3543654a5173SPeter Maydell neon_store_reg(a->vd, 1, tmp); 3544654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3545654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3546654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3547654a5173SPeter Maydell neon_store_reg(a->vd, 2, tmp3); 3548654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3549654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3550654a5173SPeter Maydell neon_store_reg(a->vd, 3, tmp2); 3551654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3552654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3553654a5173SPeter Maydell 3554654a5173SPeter Maydell return true; 3555654a5173SPeter Maydell } 355675153179SPeter Maydell 355775153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 355875153179SPeter Maydell { 355975153179SPeter Maydell int vec_size = a->q ? 16 : 8; 356075153179SPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 356175153179SPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 356275153179SPeter Maydell 356375153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 356475153179SPeter Maydell return false; 356575153179SPeter Maydell } 356675153179SPeter Maydell 356775153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 356875153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 356975153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 357075153179SPeter Maydell return false; 357175153179SPeter Maydell } 357275153179SPeter Maydell 357375153179SPeter Maydell if (a->size == 3) { 357475153179SPeter Maydell return false; 357575153179SPeter Maydell } 357675153179SPeter Maydell 357775153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 357875153179SPeter Maydell return false; 357975153179SPeter Maydell } 358075153179SPeter Maydell 358175153179SPeter Maydell if (!vfp_access_check(s)) { 358275153179SPeter Maydell return true; 358375153179SPeter Maydell } 358475153179SPeter Maydell 358575153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 358675153179SPeter Maydell 358775153179SPeter Maydell return true; 358875153179SPeter Maydell } 358975153179SPeter Maydell 359075153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 359175153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 359275153179SPeter Maydell { \ 359375153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 359475153179SPeter Maydell } 359575153179SPeter Maydell 359675153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 359775153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 359875153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 359975153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 360075153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 360175153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 360275153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 360375153179SPeter Maydell 360475153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 360575153179SPeter Maydell { 360675153179SPeter Maydell if (a->size != 0) { 360775153179SPeter Maydell return false; 360875153179SPeter Maydell } 360975153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 361075153179SPeter Maydell } 36110b30dd5bSPeter Maydell 36120b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 36130b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 36140b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 36150b30dd5bSPeter Maydell uint32_t maxsz) \ 36160b30dd5bSPeter Maydell { \ 36170b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 36180b30dd5bSPeter Maydell DATA, FUNC); \ 36190b30dd5bSPeter Maydell } 36200b30dd5bSPeter Maydell 36210b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 36220b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 36230b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 36240b30dd5bSPeter Maydell uint32_t maxsz) \ 36250b30dd5bSPeter Maydell { \ 36260b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 36270b30dd5bSPeter Maydell } 36280b30dd5bSPeter Maydell 36290b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 36300b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 36310b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 36320b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 36330b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 36340b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 36350b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 36360b30dd5bSPeter Maydell 36370b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 36380b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 36390b30dd5bSPeter Maydell { \ 36400b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 36410b30dd5bSPeter Maydell return false; \ 36420b30dd5bSPeter Maydell } \ 36430b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 36440b30dd5bSPeter Maydell } 36450b30dd5bSPeter Maydell 36460b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 36470b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 36480b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 36490b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 36500b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 36510b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 36520b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 365389668082SPeter Maydell 365489668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 365589668082SPeter Maydell { 365689668082SPeter Maydell int pass; 365789668082SPeter Maydell 365889668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 365989668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 366089668082SPeter Maydell return false; 366189668082SPeter Maydell } 366289668082SPeter Maydell 366389668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 366489668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 366589668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 366689668082SPeter Maydell return false; 366789668082SPeter Maydell } 366889668082SPeter Maydell 366989668082SPeter Maydell if (!fn) { 367089668082SPeter Maydell return false; 367189668082SPeter Maydell } 367289668082SPeter Maydell 367389668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 367489668082SPeter Maydell return false; 367589668082SPeter Maydell } 367689668082SPeter Maydell 367789668082SPeter Maydell if (!vfp_access_check(s)) { 367889668082SPeter Maydell return true; 367989668082SPeter Maydell } 368089668082SPeter Maydell 368189668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 368289668082SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 368389668082SPeter Maydell fn(tmp, tmp); 368489668082SPeter Maydell neon_store_reg(a->vd, pass, tmp); 368589668082SPeter Maydell } 368689668082SPeter Maydell 368789668082SPeter Maydell return true; 368889668082SPeter Maydell } 368989668082SPeter Maydell 369089668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 369189668082SPeter Maydell { 369289668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 369389668082SPeter Maydell tcg_gen_bswap32_i32, 369489668082SPeter Maydell gen_swap_half, 369589668082SPeter Maydell NULL, 369689668082SPeter Maydell NULL, 369789668082SPeter Maydell }; 369889668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 369989668082SPeter Maydell } 370089668082SPeter Maydell 370189668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 370289668082SPeter Maydell { 370389668082SPeter Maydell if (a->size != 0) { 370489668082SPeter Maydell return false; 370589668082SPeter Maydell } 370689668082SPeter Maydell return do_2misc(s, a, gen_rev16); 370789668082SPeter Maydell } 370884eae770SPeter Maydell 370984eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 371084eae770SPeter Maydell { 371184eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 371284eae770SPeter Maydell gen_helper_neon_cls_s8, 371384eae770SPeter Maydell gen_helper_neon_cls_s16, 371484eae770SPeter Maydell gen_helper_neon_cls_s32, 371584eae770SPeter Maydell NULL, 371684eae770SPeter Maydell }; 371784eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 371884eae770SPeter Maydell } 371984eae770SPeter Maydell 372084eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 372184eae770SPeter Maydell { 372284eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 372384eae770SPeter Maydell } 372484eae770SPeter Maydell 372584eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 372684eae770SPeter Maydell { 372784eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 372884eae770SPeter Maydell gen_helper_neon_clz_u8, 372984eae770SPeter Maydell gen_helper_neon_clz_u16, 373084eae770SPeter Maydell do_VCLZ_32, 373184eae770SPeter Maydell NULL, 373284eae770SPeter Maydell }; 373384eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 373484eae770SPeter Maydell } 373584eae770SPeter Maydell 373684eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 373784eae770SPeter Maydell { 373884eae770SPeter Maydell if (a->size != 0) { 373984eae770SPeter Maydell return false; 374084eae770SPeter Maydell } 374184eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 374284eae770SPeter Maydell } 374384eae770SPeter Maydell 374484eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 374584eae770SPeter Maydell { 374684eae770SPeter Maydell if (a->size != 2) { 374784eae770SPeter Maydell return false; 374884eae770SPeter Maydell } 374984eae770SPeter Maydell /* TODO: FP16 : size == 1 */ 375084eae770SPeter Maydell return do_2misc(s, a, gen_helper_vfp_abss); 375184eae770SPeter Maydell } 375284eae770SPeter Maydell 375384eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 375484eae770SPeter Maydell { 375584eae770SPeter Maydell if (a->size != 2) { 375684eae770SPeter Maydell return false; 375784eae770SPeter Maydell } 375884eae770SPeter Maydell /* TODO: FP16 : size == 1 */ 375984eae770SPeter Maydell return do_2misc(s, a, gen_helper_vfp_negs); 376084eae770SPeter Maydell } 376184eae770SPeter Maydell 376284eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 376384eae770SPeter Maydell { 376484eae770SPeter Maydell if (a->size != 2) { 376584eae770SPeter Maydell return false; 376684eae770SPeter Maydell } 376784eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 376884eae770SPeter Maydell } 376984eae770SPeter Maydell 377084eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 377184eae770SPeter Maydell { 377284eae770SPeter Maydell if (a->size != 2) { 377384eae770SPeter Maydell return false; 377484eae770SPeter Maydell } 377584eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 377684eae770SPeter Maydell } 37774936f38aSPeter Maydell 37784936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 37794936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 37804936f38aSPeter Maydell { \ 37814936f38aSPeter Maydell FUNC(d, cpu_env, m); \ 37824936f38aSPeter Maydell } 37834936f38aSPeter Maydell 37844936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 37854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 37864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 37874936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 37884936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 37894936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 37904936f38aSPeter Maydell 37914936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 37924936f38aSPeter Maydell { 37934936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 37944936f38aSPeter Maydell gen_VQABS_s8, 37954936f38aSPeter Maydell gen_VQABS_s16, 37964936f38aSPeter Maydell gen_VQABS_s32, 37974936f38aSPeter Maydell NULL, 37984936f38aSPeter Maydell }; 37994936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 38004936f38aSPeter Maydell } 38014936f38aSPeter Maydell 38024936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 38034936f38aSPeter Maydell { 38044936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 38054936f38aSPeter Maydell gen_VQNEG_s8, 38064936f38aSPeter Maydell gen_VQNEG_s16, 38074936f38aSPeter Maydell gen_VQNEG_s32, 38084936f38aSPeter Maydell NULL, 38094936f38aSPeter Maydell }; 38104936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 38114936f38aSPeter Maydell } 38123e96b205SPeter Maydell 38133e96b205SPeter Maydell static bool do_2misc_fp(DisasContext *s, arg_2misc *a, 38143e96b205SPeter Maydell NeonGenOneSingleOpFn *fn) 38153e96b205SPeter Maydell { 38163e96b205SPeter Maydell int pass; 38173e96b205SPeter Maydell TCGv_ptr fpst; 38183e96b205SPeter Maydell 38193e96b205SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 38203e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 38213e96b205SPeter Maydell return false; 38223e96b205SPeter Maydell } 38233e96b205SPeter Maydell 38243e96b205SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 38253e96b205SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 38263e96b205SPeter Maydell ((a->vd | a->vm) & 0x10)) { 38273e96b205SPeter Maydell return false; 38283e96b205SPeter Maydell } 38293e96b205SPeter Maydell 38303e96b205SPeter Maydell if (a->size != 2) { 38313e96b205SPeter Maydell /* TODO: FP16 will be the size == 1 case */ 38323e96b205SPeter Maydell return false; 38333e96b205SPeter Maydell } 38343e96b205SPeter Maydell 38353e96b205SPeter Maydell if ((a->vd | a->vm) & a->q) { 38363e96b205SPeter Maydell return false; 38373e96b205SPeter Maydell } 38383e96b205SPeter Maydell 38393e96b205SPeter Maydell if (!vfp_access_check(s)) { 38403e96b205SPeter Maydell return true; 38413e96b205SPeter Maydell } 38423e96b205SPeter Maydell 3843a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 38443e96b205SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 38453e96b205SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 38463e96b205SPeter Maydell fn(tmp, tmp, fpst); 38473e96b205SPeter Maydell neon_store_reg(a->vd, pass, tmp); 38483e96b205SPeter Maydell } 38493e96b205SPeter Maydell tcg_temp_free_ptr(fpst); 38503e96b205SPeter Maydell 38513e96b205SPeter Maydell return true; 38523e96b205SPeter Maydell } 38533e96b205SPeter Maydell 38543e96b205SPeter Maydell #define DO_2MISC_FP(INSN, FUNC) \ 38553e96b205SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 38563e96b205SPeter Maydell { \ 38573e96b205SPeter Maydell return do_2misc_fp(s, a, FUNC); \ 38583e96b205SPeter Maydell } 38593e96b205SPeter Maydell 38603e96b205SPeter Maydell DO_2MISC_FP(VRECPE_F, gen_helper_recpe_f32) 38613e96b205SPeter Maydell DO_2MISC_FP(VRSQRTE_F, gen_helper_rsqrte_f32) 38623e96b205SPeter Maydell DO_2MISC_FP(VCVT_FS, gen_helper_vfp_sitos) 38633e96b205SPeter Maydell DO_2MISC_FP(VCVT_FU, gen_helper_vfp_uitos) 38643e96b205SPeter Maydell DO_2MISC_FP(VCVT_SF, gen_helper_vfp_tosizs) 38653e96b205SPeter Maydell DO_2MISC_FP(VCVT_UF, gen_helper_vfp_touizs) 38663e96b205SPeter Maydell 38673e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 38683e96b205SPeter Maydell { 38693e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 38703e96b205SPeter Maydell return false; 38713e96b205SPeter Maydell } 38723e96b205SPeter Maydell return do_2misc_fp(s, a, gen_helper_rints_exact); 38733e96b205SPeter Maydell } 3874baa59323SPeter Maydell 3875baa59323SPeter Maydell #define WRAP_FP_CMP0_FWD(WRAPNAME, FUNC) \ 3876baa59323SPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ 3877baa59323SPeter Maydell { \ 3878baa59323SPeter Maydell TCGv_i32 zero = tcg_const_i32(0); \ 3879baa59323SPeter Maydell FUNC(d, m, zero, fpst); \ 3880baa59323SPeter Maydell tcg_temp_free_i32(zero); \ 3881baa59323SPeter Maydell } 3882baa59323SPeter Maydell #define WRAP_FP_CMP0_REV(WRAPNAME, FUNC) \ 3883baa59323SPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ 3884baa59323SPeter Maydell { \ 3885baa59323SPeter Maydell TCGv_i32 zero = tcg_const_i32(0); \ 3886baa59323SPeter Maydell FUNC(d, zero, m, fpst); \ 3887baa59323SPeter Maydell tcg_temp_free_i32(zero); \ 3888baa59323SPeter Maydell } 3889baa59323SPeter Maydell 3890baa59323SPeter Maydell #define DO_FP_CMP0(INSN, FUNC, REV) \ 3891baa59323SPeter Maydell WRAP_FP_CMP0_##REV(gen_##INSN, FUNC) \ 3892baa59323SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3893baa59323SPeter Maydell { \ 3894baa59323SPeter Maydell return do_2misc_fp(s, a, gen_##INSN); \ 3895baa59323SPeter Maydell } 3896baa59323SPeter Maydell 3897baa59323SPeter Maydell DO_FP_CMP0(VCGT0_F, gen_helper_neon_cgt_f32, FWD) 3898baa59323SPeter Maydell DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD) 3899baa59323SPeter Maydell DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD) 3900baa59323SPeter Maydell DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV) 3901baa59323SPeter Maydell DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV) 3902128123eaSPeter Maydell 3903128123eaSPeter Maydell static bool do_vrint(DisasContext *s, arg_2misc *a, int rmode) 3904128123eaSPeter Maydell { 3905128123eaSPeter Maydell /* 3906128123eaSPeter Maydell * Handle a VRINT* operation by iterating 32 bits at a time, 3907128123eaSPeter Maydell * with a specified rounding mode in operation. 3908128123eaSPeter Maydell */ 3909128123eaSPeter Maydell int pass; 3910128123eaSPeter Maydell TCGv_ptr fpst; 3911128123eaSPeter Maydell TCGv_i32 tcg_rmode; 3912128123eaSPeter Maydell 3913128123eaSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3914128123eaSPeter Maydell !arm_dc_feature(s, ARM_FEATURE_V8)) { 3915128123eaSPeter Maydell return false; 3916128123eaSPeter Maydell } 3917128123eaSPeter Maydell 3918128123eaSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3919128123eaSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3920128123eaSPeter Maydell ((a->vd | a->vm) & 0x10)) { 3921128123eaSPeter Maydell return false; 3922128123eaSPeter Maydell } 3923128123eaSPeter Maydell 3924128123eaSPeter Maydell if (a->size != 2) { 3925128123eaSPeter Maydell /* TODO: FP16 will be the size == 1 case */ 3926128123eaSPeter Maydell return false; 3927128123eaSPeter Maydell } 3928128123eaSPeter Maydell 3929128123eaSPeter Maydell if ((a->vd | a->vm) & a->q) { 3930128123eaSPeter Maydell return false; 3931128123eaSPeter Maydell } 3932128123eaSPeter Maydell 3933128123eaSPeter Maydell if (!vfp_access_check(s)) { 3934128123eaSPeter Maydell return true; 3935128123eaSPeter Maydell } 3936128123eaSPeter Maydell 3937a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3938128123eaSPeter Maydell tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); 3939128123eaSPeter Maydell gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); 3940128123eaSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3941128123eaSPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 3942128123eaSPeter Maydell gen_helper_rints(tmp, tmp, fpst); 3943128123eaSPeter Maydell neon_store_reg(a->vd, pass, tmp); 3944128123eaSPeter Maydell } 3945128123eaSPeter Maydell gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); 3946128123eaSPeter Maydell tcg_temp_free_i32(tcg_rmode); 3947128123eaSPeter Maydell tcg_temp_free_ptr(fpst); 3948128123eaSPeter Maydell 3949128123eaSPeter Maydell return true; 3950128123eaSPeter Maydell } 3951128123eaSPeter Maydell 3952128123eaSPeter Maydell #define DO_VRINT(INSN, RMODE) \ 3953128123eaSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3954128123eaSPeter Maydell { \ 3955128123eaSPeter Maydell return do_vrint(s, a, RMODE); \ 3956128123eaSPeter Maydell } 3957128123eaSPeter Maydell 3958128123eaSPeter Maydell DO_VRINT(VRINTN, FPROUNDING_TIEEVEN) 3959128123eaSPeter Maydell DO_VRINT(VRINTA, FPROUNDING_TIEAWAY) 3960128123eaSPeter Maydell DO_VRINT(VRINTZ, FPROUNDING_ZERO) 3961128123eaSPeter Maydell DO_VRINT(VRINTM, FPROUNDING_NEGINF) 3962128123eaSPeter Maydell DO_VRINT(VRINTP, FPROUNDING_POSINF) 3963a183d5fbSPeter Maydell 3964a183d5fbSPeter Maydell static bool do_vcvt(DisasContext *s, arg_2misc *a, int rmode, bool is_signed) 3965a183d5fbSPeter Maydell { 3966a183d5fbSPeter Maydell /* 3967a183d5fbSPeter Maydell * Handle a VCVT* operation by iterating 32 bits at a time, 3968a183d5fbSPeter Maydell * with a specified rounding mode in operation. 3969a183d5fbSPeter Maydell */ 3970a183d5fbSPeter Maydell int pass; 3971a183d5fbSPeter Maydell TCGv_ptr fpst; 3972a183d5fbSPeter Maydell TCGv_i32 tcg_rmode, tcg_shift; 3973a183d5fbSPeter Maydell 3974a183d5fbSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3975a183d5fbSPeter Maydell !arm_dc_feature(s, ARM_FEATURE_V8)) { 3976a183d5fbSPeter Maydell return false; 3977a183d5fbSPeter Maydell } 3978a183d5fbSPeter Maydell 3979a183d5fbSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3980a183d5fbSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3981a183d5fbSPeter Maydell ((a->vd | a->vm) & 0x10)) { 3982a183d5fbSPeter Maydell return false; 3983a183d5fbSPeter Maydell } 3984a183d5fbSPeter Maydell 3985a183d5fbSPeter Maydell if (a->size != 2) { 3986a183d5fbSPeter Maydell /* TODO: FP16 will be the size == 1 case */ 3987a183d5fbSPeter Maydell return false; 3988a183d5fbSPeter Maydell } 3989a183d5fbSPeter Maydell 3990a183d5fbSPeter Maydell if ((a->vd | a->vm) & a->q) { 3991a183d5fbSPeter Maydell return false; 3992a183d5fbSPeter Maydell } 3993a183d5fbSPeter Maydell 3994a183d5fbSPeter Maydell if (!vfp_access_check(s)) { 3995a183d5fbSPeter Maydell return true; 3996a183d5fbSPeter Maydell } 3997a183d5fbSPeter Maydell 3998a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3999a183d5fbSPeter Maydell tcg_shift = tcg_const_i32(0); 4000a183d5fbSPeter Maydell tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); 4001a183d5fbSPeter Maydell gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); 4002a183d5fbSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 4003a183d5fbSPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 4004a183d5fbSPeter Maydell if (is_signed) { 4005a183d5fbSPeter Maydell gen_helper_vfp_tosls(tmp, tmp, tcg_shift, fpst); 4006a183d5fbSPeter Maydell } else { 4007a183d5fbSPeter Maydell gen_helper_vfp_touls(tmp, tmp, tcg_shift, fpst); 4008a183d5fbSPeter Maydell } 4009a183d5fbSPeter Maydell neon_store_reg(a->vd, pass, tmp); 4010a183d5fbSPeter Maydell } 4011a183d5fbSPeter Maydell gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); 4012a183d5fbSPeter Maydell tcg_temp_free_i32(tcg_rmode); 4013a183d5fbSPeter Maydell tcg_temp_free_i32(tcg_shift); 4014a183d5fbSPeter Maydell tcg_temp_free_ptr(fpst); 4015a183d5fbSPeter Maydell 4016a183d5fbSPeter Maydell return true; 4017a183d5fbSPeter Maydell } 4018a183d5fbSPeter Maydell 4019a183d5fbSPeter Maydell #define DO_VCVT(INSN, RMODE, SIGNED) \ 4020a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 4021a183d5fbSPeter Maydell { \ 4022a183d5fbSPeter Maydell return do_vcvt(s, a, RMODE, SIGNED); \ 4023a183d5fbSPeter Maydell } 4024a183d5fbSPeter Maydell 4025a183d5fbSPeter Maydell DO_VCVT(VCVTAU, FPROUNDING_TIEAWAY, false) 4026a183d5fbSPeter Maydell DO_VCVT(VCVTAS, FPROUNDING_TIEAWAY, true) 4027a183d5fbSPeter Maydell DO_VCVT(VCVTNU, FPROUNDING_TIEEVEN, false) 4028a183d5fbSPeter Maydell DO_VCVT(VCVTNS, FPROUNDING_TIEEVEN, true) 4029a183d5fbSPeter Maydell DO_VCVT(VCVTPU, FPROUNDING_POSINF, false) 4030a183d5fbSPeter Maydell DO_VCVT(VCVTPS, FPROUNDING_POSINF, true) 4031a183d5fbSPeter Maydell DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false) 4032a183d5fbSPeter Maydell DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true) 40338ab3a227SPeter Maydell 40348ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 40358ab3a227SPeter Maydell { 40368ab3a227SPeter Maydell TCGv_i64 rm, rd; 40378ab3a227SPeter Maydell int pass; 40388ab3a227SPeter Maydell 40398ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 40408ab3a227SPeter Maydell return false; 40418ab3a227SPeter Maydell } 40428ab3a227SPeter Maydell 40438ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 40448ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 40458ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 40468ab3a227SPeter Maydell return false; 40478ab3a227SPeter Maydell } 40488ab3a227SPeter Maydell 40498ab3a227SPeter Maydell if (a->size != 0) { 40508ab3a227SPeter Maydell return false; 40518ab3a227SPeter Maydell } 40528ab3a227SPeter Maydell 40538ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 40548ab3a227SPeter Maydell return false; 40558ab3a227SPeter Maydell } 40568ab3a227SPeter Maydell 40578ab3a227SPeter Maydell if (!vfp_access_check(s)) { 40588ab3a227SPeter Maydell return true; 40598ab3a227SPeter Maydell } 40608ab3a227SPeter Maydell 40618ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 40628ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 40638ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 40648ab3a227SPeter Maydell neon_load_reg64(rm, a->vm + pass); 40658ab3a227SPeter Maydell neon_load_reg64(rd, a->vd + pass); 40668ab3a227SPeter Maydell neon_store_reg64(rm, a->vd + pass); 40678ab3a227SPeter Maydell neon_store_reg64(rd, a->vm + pass); 40688ab3a227SPeter Maydell } 40698ab3a227SPeter Maydell tcg_temp_free_i64(rm); 40708ab3a227SPeter Maydell tcg_temp_free_i64(rd); 40718ab3a227SPeter Maydell 40728ab3a227SPeter Maydell return true; 40738ab3a227SPeter Maydell } 4074d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 4075d4366190SPeter Maydell { 4076d4366190SPeter Maydell TCGv_i32 rd, tmp; 4077d4366190SPeter Maydell 4078d4366190SPeter Maydell rd = tcg_temp_new_i32(); 4079d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 4080d4366190SPeter Maydell 4081d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 4082d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 4083d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 4084d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 4085d4366190SPeter Maydell 4086d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 4087d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 4088d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 4089d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 4090d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 4091d4366190SPeter Maydell 4092d4366190SPeter Maydell tcg_temp_free_i32(tmp); 4093d4366190SPeter Maydell tcg_temp_free_i32(rd); 4094d4366190SPeter Maydell } 4095d4366190SPeter Maydell 4096d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 4097d4366190SPeter Maydell { 4098d4366190SPeter Maydell TCGv_i32 rd, tmp; 4099d4366190SPeter Maydell 4100d4366190SPeter Maydell rd = tcg_temp_new_i32(); 4101d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 4102d4366190SPeter Maydell 4103d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 4104d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 4105d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 4106d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 4107d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 4108d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 4109d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 4110d4366190SPeter Maydell 4111d4366190SPeter Maydell tcg_temp_free_i32(tmp); 4112d4366190SPeter Maydell tcg_temp_free_i32(rd); 4113d4366190SPeter Maydell } 4114d4366190SPeter Maydell 4115d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 4116d4366190SPeter Maydell { 4117d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 4118d4366190SPeter Maydell int pass; 4119d4366190SPeter Maydell 4120d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 4121d4366190SPeter Maydell return false; 4122d4366190SPeter Maydell } 4123d4366190SPeter Maydell 4124d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 4125d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 4126d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 4127d4366190SPeter Maydell return false; 4128d4366190SPeter Maydell } 4129d4366190SPeter Maydell 4130d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 4131d4366190SPeter Maydell return false; 4132d4366190SPeter Maydell } 4133d4366190SPeter Maydell 4134d4366190SPeter Maydell if (a->size == 3) { 4135d4366190SPeter Maydell return false; 4136d4366190SPeter Maydell } 4137d4366190SPeter Maydell 4138d4366190SPeter Maydell if (!vfp_access_check(s)) { 4139d4366190SPeter Maydell return true; 4140d4366190SPeter Maydell } 4141d4366190SPeter Maydell 4142d4366190SPeter Maydell if (a->size == 2) { 4143d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 4144d4366190SPeter Maydell tmp = neon_load_reg(a->vm, pass); 4145d4366190SPeter Maydell tmp2 = neon_load_reg(a->vd, pass + 1); 4146d4366190SPeter Maydell neon_store_reg(a->vm, pass, tmp2); 4147d4366190SPeter Maydell neon_store_reg(a->vd, pass + 1, tmp); 4148d4366190SPeter Maydell } 4149d4366190SPeter Maydell } else { 4150d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 4151d4366190SPeter Maydell tmp = neon_load_reg(a->vm, pass); 4152d4366190SPeter Maydell tmp2 = neon_load_reg(a->vd, pass); 4153d4366190SPeter Maydell if (a->size == 0) { 4154d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 4155d4366190SPeter Maydell } else { 4156d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 4157d4366190SPeter Maydell } 4158d4366190SPeter Maydell neon_store_reg(a->vm, pass, tmp2); 4159d4366190SPeter Maydell neon_store_reg(a->vd, pass, tmp); 4160d4366190SPeter Maydell } 4161d4366190SPeter Maydell } 4162d4366190SPeter Maydell return true; 4163d4366190SPeter Maydell } 4164