1625e3dd4SPeter Maydell /* 2625e3dd4SPeter Maydell * ARM translation: AArch32 Neon instructions 3625e3dd4SPeter Maydell * 4625e3dd4SPeter Maydell * Copyright (c) 2003 Fabrice Bellard 5625e3dd4SPeter Maydell * Copyright (c) 2005-2007 CodeSourcery 6625e3dd4SPeter Maydell * Copyright (c) 2007 OpenedHand, Ltd. 7625e3dd4SPeter Maydell * Copyright (c) 2020 Linaro, Ltd. 8625e3dd4SPeter Maydell * 9625e3dd4SPeter Maydell * This library is free software; you can redistribute it and/or 10625e3dd4SPeter Maydell * modify it under the terms of the GNU Lesser General Public 11625e3dd4SPeter Maydell * License as published by the Free Software Foundation; either 1250f57e09SChetan Pant * version 2.1 of the License, or (at your option) any later version. 13625e3dd4SPeter Maydell * 14625e3dd4SPeter Maydell * This library is distributed in the hope that it will be useful, 15625e3dd4SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 16625e3dd4SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17625e3dd4SPeter Maydell * Lesser General Public License for more details. 18625e3dd4SPeter Maydell * 19625e3dd4SPeter Maydell * You should have received a copy of the GNU Lesser General Public 20625e3dd4SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21625e3dd4SPeter Maydell */ 22625e3dd4SPeter Maydell 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 526cf0f240SPeter Maydell static inline int neon_3same_fp_size(DisasContext *s, int x) 536cf0f240SPeter Maydell { 546cf0f240SPeter Maydell /* Convert 0==fp32, 1==fp16 into a MO_* value */ 556cf0f240SPeter Maydell return MO_32 - x; 566cf0f240SPeter Maydell } 576cf0f240SPeter Maydell 58625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 59139c1837SPaolo Bonzini #include "decode-neon-dp.c.inc" 60139c1837SPaolo Bonzini #include "decode-neon-ls.c.inc" 61139c1837SPaolo Bonzini #include "decode-neon-shared.c.inc" 62afff8de0SPeter Maydell 636fb57878SPeter Maydell static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) 646fb57878SPeter Maydell { 656fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 666fb57878SPeter Maydell 676fb57878SPeter Maydell switch (mop) { 686fb57878SPeter Maydell case MO_UB: 696fb57878SPeter Maydell tcg_gen_ld8u_i32(var, cpu_env, offset); 706fb57878SPeter Maydell break; 716fb57878SPeter Maydell case MO_UW: 726fb57878SPeter Maydell tcg_gen_ld16u_i32(var, cpu_env, offset); 736fb57878SPeter Maydell break; 746fb57878SPeter Maydell case MO_UL: 756fb57878SPeter Maydell tcg_gen_ld_i32(var, cpu_env, offset); 766fb57878SPeter Maydell break; 776fb57878SPeter Maydell default: 786fb57878SPeter Maydell g_assert_not_reached(); 796fb57878SPeter Maydell } 806fb57878SPeter Maydell } 816fb57878SPeter Maydell 826fb57878SPeter Maydell static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) 836fb57878SPeter Maydell { 846fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, mop & MO_SIZE); 856fb57878SPeter Maydell 866fb57878SPeter Maydell switch (mop) { 876fb57878SPeter Maydell case MO_UB: 886fb57878SPeter Maydell tcg_gen_ld8u_i64(var, cpu_env, offset); 896fb57878SPeter Maydell break; 906fb57878SPeter Maydell case MO_UW: 916fb57878SPeter Maydell tcg_gen_ld16u_i64(var, cpu_env, offset); 926fb57878SPeter Maydell break; 936fb57878SPeter Maydell case MO_UL: 946fb57878SPeter Maydell tcg_gen_ld32u_i64(var, cpu_env, offset); 956fb57878SPeter Maydell break; 966fb57878SPeter Maydell case MO_Q: 976fb57878SPeter Maydell tcg_gen_ld_i64(var, cpu_env, offset); 986fb57878SPeter Maydell break; 996fb57878SPeter Maydell default: 1006fb57878SPeter Maydell g_assert_not_reached(); 1016fb57878SPeter Maydell } 1026fb57878SPeter Maydell } 1036fb57878SPeter Maydell 1046fb57878SPeter Maydell static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) 1056fb57878SPeter Maydell { 1066fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1076fb57878SPeter Maydell 1086fb57878SPeter Maydell switch (size) { 1096fb57878SPeter Maydell case MO_8: 1106fb57878SPeter Maydell tcg_gen_st8_i32(var, cpu_env, offset); 1116fb57878SPeter Maydell break; 1126fb57878SPeter Maydell case MO_16: 1136fb57878SPeter Maydell tcg_gen_st16_i32(var, cpu_env, offset); 1146fb57878SPeter Maydell break; 1156fb57878SPeter Maydell case MO_32: 1166fb57878SPeter Maydell tcg_gen_st_i32(var, cpu_env, offset); 1176fb57878SPeter Maydell break; 1186fb57878SPeter Maydell default: 1196fb57878SPeter Maydell g_assert_not_reached(); 1206fb57878SPeter Maydell } 1216fb57878SPeter Maydell } 1226fb57878SPeter Maydell 1236fb57878SPeter Maydell static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) 1246fb57878SPeter Maydell { 1256fb57878SPeter Maydell long offset = neon_element_offset(reg, ele, size); 1266fb57878SPeter Maydell 1276fb57878SPeter Maydell switch (size) { 1286fb57878SPeter Maydell case MO_8: 1296fb57878SPeter Maydell tcg_gen_st8_i64(var, cpu_env, offset); 1306fb57878SPeter Maydell break; 1316fb57878SPeter Maydell case MO_16: 1326fb57878SPeter Maydell tcg_gen_st16_i64(var, cpu_env, offset); 1336fb57878SPeter Maydell break; 1346fb57878SPeter Maydell case MO_32: 1356fb57878SPeter Maydell tcg_gen_st32_i64(var, cpu_env, offset); 1366fb57878SPeter Maydell break; 1376fb57878SPeter Maydell case MO_64: 1386fb57878SPeter Maydell tcg_gen_st_i64(var, cpu_env, offset); 1396fb57878SPeter Maydell break; 1406fb57878SPeter Maydell default: 1416fb57878SPeter Maydell g_assert_not_reached(); 1426fb57878SPeter Maydell } 1436fb57878SPeter Maydell } 1446fb57878SPeter Maydell 145afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 146afff8de0SPeter Maydell { 147afff8de0SPeter Maydell int opr_sz; 148afff8de0SPeter Maydell TCGv_ptr fpst; 149afff8de0SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 150afff8de0SPeter Maydell 151afff8de0SPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 152d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 153afff8de0SPeter Maydell return false; 154afff8de0SPeter Maydell } 155afff8de0SPeter Maydell 156afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 157afff8de0SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 158afff8de0SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 159afff8de0SPeter Maydell return false; 160afff8de0SPeter Maydell } 161afff8de0SPeter Maydell 162afff8de0SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 163afff8de0SPeter Maydell return false; 164afff8de0SPeter Maydell } 165afff8de0SPeter Maydell 166afff8de0SPeter Maydell if (!vfp_access_check(s)) { 167afff8de0SPeter Maydell return true; 168afff8de0SPeter Maydell } 169afff8de0SPeter Maydell 170afff8de0SPeter Maydell opr_sz = (1 + a->q) * 8; 171d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 172d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 173d186a485SPeter Maydell gen_helper_gvec_fcmlah : gen_helper_gvec_fcmlas; 174afff8de0SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 175afff8de0SPeter Maydell vfp_reg_offset(1, a->vn), 176afff8de0SPeter Maydell vfp_reg_offset(1, a->vm), 177afff8de0SPeter Maydell fpst, opr_sz, opr_sz, a->rot, 178afff8de0SPeter Maydell fn_gvec_ptr); 179afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 180afff8de0SPeter Maydell return true; 181afff8de0SPeter Maydell } 18294d5eb7bSPeter Maydell 18394d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 18494d5eb7bSPeter Maydell { 18594d5eb7bSPeter Maydell int opr_sz; 18694d5eb7bSPeter Maydell TCGv_ptr fpst; 18794d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 18894d5eb7bSPeter Maydell 18994d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 190d186a485SPeter Maydell || (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s))) { 19194d5eb7bSPeter Maydell return false; 19294d5eb7bSPeter Maydell } 19394d5eb7bSPeter Maydell 19494d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 19594d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 19694d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 19794d5eb7bSPeter Maydell return false; 19894d5eb7bSPeter Maydell } 19994d5eb7bSPeter Maydell 20094d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 20194d5eb7bSPeter Maydell return false; 20294d5eb7bSPeter Maydell } 20394d5eb7bSPeter Maydell 20494d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 20594d5eb7bSPeter Maydell return true; 20694d5eb7bSPeter Maydell } 20794d5eb7bSPeter Maydell 20894d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 209d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 210d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 211d186a485SPeter Maydell gen_helper_gvec_fcaddh : gen_helper_gvec_fcadds; 21294d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 21394d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 21494d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 21594d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 21694d5eb7bSPeter Maydell fn_gvec_ptr); 21794d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 21894d5eb7bSPeter Maydell return true; 21994d5eb7bSPeter Maydell } 22032da0e33SPeter Maydell 22132da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a) 22232da0e33SPeter Maydell { 22332da0e33SPeter Maydell int opr_sz; 22432da0e33SPeter Maydell gen_helper_gvec_3 *fn_gvec; 22532da0e33SPeter Maydell 22632da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 22732da0e33SPeter Maydell return false; 22832da0e33SPeter Maydell } 22932da0e33SPeter Maydell 23032da0e33SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 23132da0e33SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 23232da0e33SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 23332da0e33SPeter Maydell return false; 23432da0e33SPeter Maydell } 23532da0e33SPeter Maydell 23632da0e33SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 23732da0e33SPeter Maydell return false; 23832da0e33SPeter Maydell } 23932da0e33SPeter Maydell 24032da0e33SPeter Maydell if (!vfp_access_check(s)) { 24132da0e33SPeter Maydell return true; 24232da0e33SPeter Maydell } 24332da0e33SPeter Maydell 24432da0e33SPeter Maydell opr_sz = (1 + a->q) * 8; 24532da0e33SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; 24632da0e33SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 24732da0e33SPeter Maydell vfp_reg_offset(1, a->vn), 24832da0e33SPeter Maydell vfp_reg_offset(1, a->vm), 24932da0e33SPeter Maydell opr_sz, opr_sz, 0, fn_gvec); 25032da0e33SPeter Maydell return true; 25132da0e33SPeter Maydell } 2529a107e7bSPeter Maydell 2539a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 2549a107e7bSPeter Maydell { 2559a107e7bSPeter Maydell int opr_sz; 2569a107e7bSPeter Maydell 2579a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 2589a107e7bSPeter Maydell return false; 2599a107e7bSPeter Maydell } 2609a107e7bSPeter Maydell 2619a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2629a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2639a107e7bSPeter Maydell (a->vd & 0x10)) { 2649a107e7bSPeter Maydell return false; 2659a107e7bSPeter Maydell } 2669a107e7bSPeter Maydell 2679a107e7bSPeter Maydell if (a->vd & a->q) { 2689a107e7bSPeter Maydell return false; 2699a107e7bSPeter Maydell } 2709a107e7bSPeter Maydell 2719a107e7bSPeter Maydell if (!vfp_access_check(s)) { 2729a107e7bSPeter Maydell return true; 2739a107e7bSPeter Maydell } 2749a107e7bSPeter Maydell 2759a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 2769a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 2779a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 2789a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 2799a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 2809a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 2819a107e7bSPeter Maydell return true; 2829a107e7bSPeter Maydell } 2837e1b5d61SPeter Maydell 2847e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 2857e1b5d61SPeter Maydell { 2867e1b5d61SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 2877e1b5d61SPeter Maydell int opr_sz; 2887e1b5d61SPeter Maydell TCGv_ptr fpst; 2897e1b5d61SPeter Maydell 2907e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 2917e1b5d61SPeter Maydell return false; 2927e1b5d61SPeter Maydell } 293d186a485SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { 2947e1b5d61SPeter Maydell return false; 2957e1b5d61SPeter Maydell } 2967e1b5d61SPeter Maydell 2977e1b5d61SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2987e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2997e1b5d61SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 3007e1b5d61SPeter Maydell return false; 3017e1b5d61SPeter Maydell } 3027e1b5d61SPeter Maydell 3037e1b5d61SPeter Maydell if ((a->vd | a->vn) & a->q) { 3047e1b5d61SPeter Maydell return false; 3057e1b5d61SPeter Maydell } 3067e1b5d61SPeter Maydell 3077e1b5d61SPeter Maydell if (!vfp_access_check(s)) { 3087e1b5d61SPeter Maydell return true; 3097e1b5d61SPeter Maydell } 3107e1b5d61SPeter Maydell 311d186a485SPeter Maydell fn_gvec_ptr = (a->size == MO_16) ? 312d186a485SPeter Maydell gen_helper_gvec_fcmlah_idx : gen_helper_gvec_fcmlas_idx; 3137e1b5d61SPeter Maydell opr_sz = (1 + a->q) * 8; 314d186a485SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 3157e1b5d61SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 3167e1b5d61SPeter Maydell vfp_reg_offset(1, a->vn), 3177e1b5d61SPeter Maydell vfp_reg_offset(1, a->vm), 3187e1b5d61SPeter Maydell fpst, opr_sz, opr_sz, 3197e1b5d61SPeter Maydell (a->index << 2) | a->rot, fn_gvec_ptr); 3207e1b5d61SPeter Maydell tcg_temp_free_ptr(fpst); 3217e1b5d61SPeter Maydell return true; 3227e1b5d61SPeter Maydell } 32335f5d4d1SPeter Maydell 32435f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) 32535f5d4d1SPeter Maydell { 32635f5d4d1SPeter Maydell gen_helper_gvec_3 *fn_gvec; 32735f5d4d1SPeter Maydell int opr_sz; 32835f5d4d1SPeter Maydell TCGv_ptr fpst; 32935f5d4d1SPeter Maydell 33035f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 33135f5d4d1SPeter Maydell return false; 33235f5d4d1SPeter Maydell } 33335f5d4d1SPeter Maydell 33435f5d4d1SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 33535f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 33635f5d4d1SPeter Maydell ((a->vd | a->vn) & 0x10)) { 33735f5d4d1SPeter Maydell return false; 33835f5d4d1SPeter Maydell } 33935f5d4d1SPeter Maydell 34035f5d4d1SPeter Maydell if ((a->vd | a->vn) & a->q) { 34135f5d4d1SPeter Maydell return false; 34235f5d4d1SPeter Maydell } 34335f5d4d1SPeter Maydell 34435f5d4d1SPeter Maydell if (!vfp_access_check(s)) { 34535f5d4d1SPeter Maydell return true; 34635f5d4d1SPeter Maydell } 34735f5d4d1SPeter Maydell 34835f5d4d1SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; 34935f5d4d1SPeter Maydell opr_sz = (1 + a->q) * 8; 350a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 35135f5d4d1SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 35235f5d4d1SPeter Maydell vfp_reg_offset(1, a->vn), 35335f5d4d1SPeter Maydell vfp_reg_offset(1, a->rm), 35435f5d4d1SPeter Maydell opr_sz, opr_sz, a->index, fn_gvec); 35535f5d4d1SPeter Maydell tcg_temp_free_ptr(fpst); 35635f5d4d1SPeter Maydell return true; 35735f5d4d1SPeter Maydell } 358d27e82f7SPeter Maydell 359d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 360d27e82f7SPeter Maydell { 361d27e82f7SPeter Maydell int opr_sz; 362d27e82f7SPeter Maydell 363d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 364d27e82f7SPeter Maydell return false; 365d27e82f7SPeter Maydell } 366d27e82f7SPeter Maydell 367d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 368d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 369d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 370d27e82f7SPeter Maydell return false; 371d27e82f7SPeter Maydell } 372d27e82f7SPeter Maydell 373d27e82f7SPeter Maydell if (a->vd & a->q) { 374d27e82f7SPeter Maydell return false; 375d27e82f7SPeter Maydell } 376d27e82f7SPeter Maydell 377d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 378d27e82f7SPeter Maydell return true; 379d27e82f7SPeter Maydell } 380d27e82f7SPeter Maydell 381d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 382d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 383d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 384d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 385d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 386d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 387d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 388d27e82f7SPeter Maydell return true; 389d27e82f7SPeter Maydell } 390a27b4630SPeter Maydell 391a27b4630SPeter Maydell static struct { 392a27b4630SPeter Maydell int nregs; 393a27b4630SPeter Maydell int interleave; 394a27b4630SPeter Maydell int spacing; 395a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 396a27b4630SPeter Maydell {1, 4, 1}, 397a27b4630SPeter Maydell {1, 4, 2}, 398a27b4630SPeter Maydell {4, 1, 1}, 399a27b4630SPeter Maydell {2, 2, 2}, 400a27b4630SPeter Maydell {1, 3, 1}, 401a27b4630SPeter Maydell {1, 3, 2}, 402a27b4630SPeter Maydell {3, 1, 1}, 403a27b4630SPeter Maydell {1, 1, 1}, 404a27b4630SPeter Maydell {1, 2, 1}, 405a27b4630SPeter Maydell {1, 2, 2}, 406a27b4630SPeter Maydell {2, 1, 1} 407a27b4630SPeter Maydell }; 408a27b4630SPeter Maydell 409a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 410a27b4630SPeter Maydell int stride) 411a27b4630SPeter Maydell { 412a27b4630SPeter Maydell if (rm != 15) { 413a27b4630SPeter Maydell TCGv_i32 base; 414a27b4630SPeter Maydell 415a27b4630SPeter Maydell base = load_reg(s, rn); 416a27b4630SPeter Maydell if (rm == 13) { 417a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 418a27b4630SPeter Maydell } else { 419a27b4630SPeter Maydell TCGv_i32 index; 420a27b4630SPeter Maydell index = load_reg(s, rm); 421a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 422a27b4630SPeter Maydell tcg_temp_free_i32(index); 423a27b4630SPeter Maydell } 424a27b4630SPeter Maydell store_reg(s, rn, base); 425a27b4630SPeter Maydell } 426a27b4630SPeter Maydell } 427a27b4630SPeter Maydell 428a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 429a27b4630SPeter Maydell { 430a27b4630SPeter Maydell /* Neon load/store multiple structures */ 431a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 432a27b4630SPeter Maydell MemOp endian = s->be_data; 433a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 434a27b4630SPeter Maydell int size = a->size; 435a27b4630SPeter Maydell TCGv_i64 tmp64; 436a27b4630SPeter Maydell TCGv_i32 addr, tmp; 437a27b4630SPeter Maydell 438a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 439a27b4630SPeter Maydell return false; 440a27b4630SPeter Maydell } 441a27b4630SPeter Maydell 442a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 443a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 444a27b4630SPeter Maydell return false; 445a27b4630SPeter Maydell } 446a27b4630SPeter Maydell if (a->itype > 10) { 447a27b4630SPeter Maydell return false; 448a27b4630SPeter Maydell } 449a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 450a27b4630SPeter Maydell switch (a->itype & 0xc) { 451a27b4630SPeter Maydell case 4: 452a27b4630SPeter Maydell if (a->align >= 2) { 453a27b4630SPeter Maydell return false; 454a27b4630SPeter Maydell } 455a27b4630SPeter Maydell break; 456a27b4630SPeter Maydell case 8: 457a27b4630SPeter Maydell if (a->align == 3) { 458a27b4630SPeter Maydell return false; 459a27b4630SPeter Maydell } 460a27b4630SPeter Maydell break; 461a27b4630SPeter Maydell default: 462a27b4630SPeter Maydell break; 463a27b4630SPeter Maydell } 464a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 465a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 466a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 467a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 468a27b4630SPeter Maydell return false; 469a27b4630SPeter Maydell } 470a27b4630SPeter Maydell 471a27b4630SPeter Maydell if (!vfp_access_check(s)) { 472a27b4630SPeter Maydell return true; 473a27b4630SPeter Maydell } 474a27b4630SPeter Maydell 475a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 476a27b4630SPeter Maydell if (size == 0) { 477a27b4630SPeter Maydell endian = MO_LE; 478a27b4630SPeter Maydell } 479a27b4630SPeter Maydell /* 480a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 481a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 482a27b4630SPeter Maydell */ 483a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 484a27b4630SPeter Maydell size = 3; 485a27b4630SPeter Maydell } 486a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 487a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 488a27b4630SPeter Maydell tmp = tcg_const_i32(1 << size); 489a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 490a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 491a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 492a27b4630SPeter Maydell int xs; 493a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 494a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 495a27b4630SPeter Maydell 496a27b4630SPeter Maydell if (a->l) { 497a27b4630SPeter Maydell gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); 498a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 499a27b4630SPeter Maydell } else { 500a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 501a27b4630SPeter Maydell gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); 502a27b4630SPeter Maydell } 503a27b4630SPeter Maydell tcg_gen_add_i32(addr, addr, tmp); 504a27b4630SPeter Maydell } 505a27b4630SPeter Maydell } 506a27b4630SPeter Maydell } 507a27b4630SPeter Maydell tcg_temp_free_i32(addr); 508a27b4630SPeter Maydell tcg_temp_free_i32(tmp); 509a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 510a27b4630SPeter Maydell 511a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 512a27b4630SPeter Maydell return true; 513a27b4630SPeter Maydell } 5143698747cSPeter Maydell 5153698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 5163698747cSPeter Maydell { 5173698747cSPeter Maydell /* Neon load single structure to all lanes */ 5183698747cSPeter Maydell int reg, stride, vec_size; 5193698747cSPeter Maydell int vd = a->vd; 5203698747cSPeter Maydell int size = a->size; 5213698747cSPeter Maydell int nregs = a->n + 1; 5223698747cSPeter Maydell TCGv_i32 addr, tmp; 5233698747cSPeter Maydell 5243698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 5253698747cSPeter Maydell return false; 5263698747cSPeter Maydell } 5273698747cSPeter Maydell 5283698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 5293698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 5303698747cSPeter Maydell return false; 5313698747cSPeter Maydell } 5323698747cSPeter Maydell 5333698747cSPeter Maydell if (size == 3) { 5343698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 5353698747cSPeter Maydell return false; 5363698747cSPeter Maydell } 5373698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 5383698747cSPeter Maydell size = 2; 5393698747cSPeter Maydell } 5403698747cSPeter Maydell if (nregs == 1 && a->a == 1 && size == 0) { 5413698747cSPeter Maydell return false; 5423698747cSPeter Maydell } 5433698747cSPeter Maydell if (nregs == 3 && a->a == 1) { 5443698747cSPeter Maydell return false; 5453698747cSPeter Maydell } 5463698747cSPeter Maydell 5473698747cSPeter Maydell if (!vfp_access_check(s)) { 5483698747cSPeter Maydell return true; 5493698747cSPeter Maydell } 5503698747cSPeter Maydell 5513698747cSPeter Maydell /* 5523698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 5533698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 5543698747cSPeter Maydell */ 5553698747cSPeter Maydell stride = a->t ? 2 : 1; 5563698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 5573698747cSPeter Maydell 5583698747cSPeter Maydell tmp = tcg_temp_new_i32(); 5593698747cSPeter Maydell addr = tcg_temp_new_i32(); 5603698747cSPeter Maydell load_reg_var(s, addr, a->rn); 5613698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 5623698747cSPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 5633698747cSPeter Maydell s->be_data | size); 5643698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 5653698747cSPeter Maydell /* 5663698747cSPeter Maydell * We cannot write 16 bytes at once because the 5673698747cSPeter Maydell * destination is unaligned. 5683698747cSPeter Maydell */ 569015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 5703698747cSPeter Maydell 8, 8, tmp); 571015ee81aSRichard Henderson tcg_gen_gvec_mov(0, neon_full_reg_offset(vd + 1), 572015ee81aSRichard Henderson neon_full_reg_offset(vd), 8, 8); 5733698747cSPeter Maydell } else { 574015ee81aSRichard Henderson tcg_gen_gvec_dup_i32(size, neon_full_reg_offset(vd), 5753698747cSPeter Maydell vec_size, vec_size, tmp); 5763698747cSPeter Maydell } 5773698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 5783698747cSPeter Maydell vd += stride; 5793698747cSPeter Maydell } 5803698747cSPeter Maydell tcg_temp_free_i32(tmp); 5813698747cSPeter Maydell tcg_temp_free_i32(addr); 5823698747cSPeter Maydell 5833698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 5843698747cSPeter Maydell 5853698747cSPeter Maydell return true; 5863698747cSPeter Maydell } 587123ce4e3SPeter Maydell 588123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 589123ce4e3SPeter Maydell { 590123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 591123ce4e3SPeter Maydell int reg; 592123ce4e3SPeter Maydell int nregs = a->n + 1; 593123ce4e3SPeter Maydell int vd = a->vd; 594123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 595123ce4e3SPeter Maydell 596123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 597123ce4e3SPeter Maydell return false; 598123ce4e3SPeter Maydell } 599123ce4e3SPeter Maydell 600123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 601123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 602123ce4e3SPeter Maydell return false; 603123ce4e3SPeter Maydell } 604123ce4e3SPeter Maydell 605123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 606123ce4e3SPeter Maydell switch (nregs) { 607123ce4e3SPeter Maydell case 1: 608123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 609*a736cbc3SRichard Henderson (a->size == 2 && (a->align == 1 || a->align == 2))) { 610123ce4e3SPeter Maydell return false; 611123ce4e3SPeter Maydell } 612123ce4e3SPeter Maydell break; 613123ce4e3SPeter Maydell case 3: 614123ce4e3SPeter Maydell if ((a->align & 1) != 0) { 615123ce4e3SPeter Maydell return false; 616123ce4e3SPeter Maydell } 617123ce4e3SPeter Maydell /* fall through */ 618123ce4e3SPeter Maydell case 2: 619123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 620123ce4e3SPeter Maydell return false; 621123ce4e3SPeter Maydell } 622123ce4e3SPeter Maydell break; 623123ce4e3SPeter Maydell case 4: 624*a736cbc3SRichard Henderson if (a->size == 2 && a->align == 3) { 625123ce4e3SPeter Maydell return false; 626123ce4e3SPeter Maydell } 627123ce4e3SPeter Maydell break; 628123ce4e3SPeter Maydell default: 629123ce4e3SPeter Maydell abort(); 630123ce4e3SPeter Maydell } 631123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 632123ce4e3SPeter Maydell /* 633123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 634123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 635123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 636123ce4e3SPeter Maydell */ 637123ce4e3SPeter Maydell return false; 638123ce4e3SPeter Maydell } 639123ce4e3SPeter Maydell 640123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 641123ce4e3SPeter Maydell return true; 642123ce4e3SPeter Maydell } 643123ce4e3SPeter Maydell 644123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 645123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 646123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 647123ce4e3SPeter Maydell /* 648123ce4e3SPeter Maydell * TODO: if we implemented alignment exceptions, we should check 649123ce4e3SPeter Maydell * addr against the alignment encoded in a->align here. 650123ce4e3SPeter Maydell */ 651123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 652123ce4e3SPeter Maydell if (a->l) { 653123ce4e3SPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 654123ce4e3SPeter Maydell s->be_data | a->size); 655123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 656123ce4e3SPeter Maydell } else { /* Store */ 657123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 658123ce4e3SPeter Maydell gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), 659123ce4e3SPeter Maydell s->be_data | a->size); 660123ce4e3SPeter Maydell } 661123ce4e3SPeter Maydell vd += a->stride; 662123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 663123ce4e3SPeter Maydell } 664123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 665123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 666123ce4e3SPeter Maydell 667123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 668123ce4e3SPeter Maydell 669123ce4e3SPeter Maydell return true; 670123ce4e3SPeter Maydell } 671a4e143acSPeter Maydell 672a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 673a4e143acSPeter Maydell { 674a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 675015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 676015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 677015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 678a4e143acSPeter Maydell 679a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 680a4e143acSPeter Maydell return false; 681a4e143acSPeter Maydell } 682a4e143acSPeter Maydell 683a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 684a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 685a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 686a4e143acSPeter Maydell return false; 687a4e143acSPeter Maydell } 688a4e143acSPeter Maydell 689a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 690a4e143acSPeter Maydell return false; 691a4e143acSPeter Maydell } 692a4e143acSPeter Maydell 693a4e143acSPeter Maydell if (!vfp_access_check(s)) { 694a4e143acSPeter Maydell return true; 695a4e143acSPeter Maydell } 696a4e143acSPeter Maydell 697a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 698a4e143acSPeter Maydell return true; 699a4e143acSPeter Maydell } 700a4e143acSPeter Maydell 701a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 702a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 703a4e143acSPeter Maydell { \ 704a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 705a4e143acSPeter Maydell } 706a4e143acSPeter Maydell 707a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 708a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 70935a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 71035a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 71135a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 71235a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 71335a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 7148161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 7158161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 716c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 717c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 718c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 719c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 72035a548edSPeter Maydell 72135a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 72235a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 72335a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 72435a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 72535a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 72635a548edSPeter Maydell { \ 72735a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 72835a548edSPeter Maydell } \ 72935a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 73035a548edSPeter Maydell 73135a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 73235a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 73335a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 73436b59310SPeter Maydell 73536b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 73636b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 73736b59310SPeter Maydell { \ 73836b59310SPeter Maydell if (a->size == 3) { \ 73936b59310SPeter Maydell return false; \ 74036b59310SPeter Maydell } \ 74136b59310SPeter Maydell return do_3same(s, a, FUNC); \ 74236b59310SPeter Maydell } 74336b59310SPeter Maydell 74436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 74536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 74636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 74736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 7480de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 74927106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 75027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 7518161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 7527715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 7537715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 7547715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 7557715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 75602bd0cdbSPeter Maydell 75702bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 75802bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 75902bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 76002bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 76102bd0cdbSPeter Maydell { \ 76202bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 76302bd0cdbSPeter Maydell } \ 76402bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 76502bd0cdbSPeter Maydell 76602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 76702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 76802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 76902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 77002bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 77102bd0cdbSPeter Maydell 772effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 773effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 774effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 775effa992fSRichard Henderson { \ 776effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 7770de34fd4SPeter Maydell } 7780de34fd4SPeter Maydell 779effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 780effa992fSRichard Henderson 7810de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 7820de34fd4SPeter Maydell { 7830de34fd4SPeter Maydell if (a->size != 0) { 7840de34fd4SPeter Maydell return false; 7850de34fd4SPeter Maydell } 7860de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 7870de34fd4SPeter Maydell } 788a0635695SPeter Maydell 789a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 790a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 791a0635695SPeter Maydell { \ 792a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 793a0635695SPeter Maydell return false; \ 794a0635695SPeter Maydell } \ 795a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 796a0635695SPeter Maydell return false; \ 797a0635695SPeter Maydell } \ 798a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 799a0635695SPeter Maydell } 800a0635695SPeter Maydell 801a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 802a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 80321290edfSPeter Maydell 804afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 805afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 806afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 807afc8b7d3SRichard Henderson { \ 808afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 809afc8b7d3SRichard Henderson return false; \ 810afc8b7d3SRichard Henderson } \ 811afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 81221290edfSPeter Maydell } 81321290edfSPeter Maydell 814afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 815afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 816afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 817afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 81821290edfSPeter Maydell 819effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 820effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 821effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 822effa992fSRichard Henderson { \ 823effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 824effa992fSRichard Henderson return false; \ 825effa992fSRichard Henderson } \ 826effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 82721290edfSPeter Maydell } 82821290edfSPeter Maydell 829effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 830effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 831effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 83235d4352fSPeter Maydell 83335d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 83435d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 83535d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 83635d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 83735d4352fSPeter Maydell { \ 83835d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 83935d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 84035d4352fSPeter Maydell } \ 84135d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 84235d4352fSPeter Maydell 84335d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 84435d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 84535d4352fSPeter Maydell { \ 84635d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 84735d4352fSPeter Maydell } \ 84835d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 84935d4352fSPeter Maydell 85035d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 85135d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 85235d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 85335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 85435d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 85535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 856cb294bcaSPeter Maydell 857cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 858cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 859cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 860cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 861cb294bcaSPeter Maydell { \ 862cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 863cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 864cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 865cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 866cb294bcaSPeter Maydell { 0 }, \ 867cb294bcaSPeter Maydell }; \ 868cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 869cb294bcaSPeter Maydell } \ 870cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 871cb294bcaSPeter Maydell { \ 872cb294bcaSPeter Maydell if (a->size > 2) { \ 873cb294bcaSPeter Maydell return false; \ 874cb294bcaSPeter Maydell } \ 875cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 876cb294bcaSPeter Maydell } 877cb294bcaSPeter Maydell 8786812dfdcSPeter Maydell /* 8796812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 8806812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 8816812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 8826812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 8836812dfdcSPeter Maydell */ 8846812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 8856812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 8866812dfdcSPeter Maydell { \ 8876812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 8886812dfdcSPeter Maydell } 8896812dfdcSPeter Maydell 8906812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 8916812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 8926812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 8936812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 8946812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 8956812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 8966812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 8976812dfdcSPeter Maydell { \ 8986812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 8996812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 9006812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9016812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9026812dfdcSPeter Maydell { 0 }, \ 9036812dfdcSPeter Maydell }; \ 9046812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 9056812dfdcSPeter Maydell } \ 9066812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9076812dfdcSPeter Maydell { \ 9086812dfdcSPeter Maydell if (a->size > 2) { \ 9096812dfdcSPeter Maydell return false; \ 9106812dfdcSPeter Maydell } \ 9116812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 9126812dfdcSPeter Maydell } 9136812dfdcSPeter Maydell 914cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 915cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 9168e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 9178e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 9188e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 9198e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 9206812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 9216812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 9226812dfdcSPeter Maydell 9236812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 9246812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 9256812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 9266812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 927059c2398SPeter Maydell 928059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 929059c2398SPeter Maydell { 930059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 931059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 932059c2398SPeter Maydell 933059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 934059c2398SPeter Maydell return false; 935059c2398SPeter Maydell } 936059c2398SPeter Maydell 937059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 938059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 939059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 940059c2398SPeter Maydell return false; 941059c2398SPeter Maydell } 942059c2398SPeter Maydell 943059c2398SPeter Maydell if (a->size == 3) { 944059c2398SPeter Maydell return false; 945059c2398SPeter Maydell } 946059c2398SPeter Maydell 947059c2398SPeter Maydell if (!vfp_access_check(s)) { 948059c2398SPeter Maydell return true; 949059c2398SPeter Maydell } 950059c2398SPeter Maydell 951059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 952059c2398SPeter Maydell 953059c2398SPeter Maydell /* 954059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 955059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 956059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 957059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 958059c2398SPeter Maydell */ 959a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 960a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 961a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 962a712266fSRichard Henderson 963a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 964a712266fSRichard Henderson read_neon_element32(tmp2, a->vn, 1, MO_32); 965059c2398SPeter Maydell fn(tmp, tmp, tmp2); 966059c2398SPeter Maydell 967a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 0, MO_32); 968a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 969059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 970059c2398SPeter Maydell 971a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 0, MO_32); 972a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 973a712266fSRichard Henderson 974a712266fSRichard Henderson tcg_temp_free_i32(tmp); 975a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 976a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 977059c2398SPeter Maydell return true; 978059c2398SPeter Maydell } 979059c2398SPeter Maydell 980059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 981059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 982059c2398SPeter Maydell { \ 983059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 984059c2398SPeter Maydell gen_helper_neon_##func##8, \ 985059c2398SPeter Maydell gen_helper_neon_##func##16, \ 986059c2398SPeter Maydell gen_helper_neon_##func##32, \ 987059c2398SPeter Maydell }; \ 988059c2398SPeter Maydell if (a->size > 2) { \ 989059c2398SPeter Maydell return false; \ 990059c2398SPeter Maydell } \ 991059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 992059c2398SPeter Maydell } 993059c2398SPeter Maydell 994059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 995059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 996059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 997059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 998059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 999fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 1000059c2398SPeter Maydell 1001059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 1002059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 1003059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 1004059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 1005fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 10067ecc28bcSPeter Maydell 10077ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 10087ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 10097ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 10107ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 10117ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 10127ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 10137ecc28bcSPeter Maydell { \ 10147ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 10157ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 10167ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 10177ecc28bcSPeter Maydell }; \ 10187ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 10197ecc28bcSPeter Maydell } \ 10207ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 10217ecc28bcSPeter Maydell { \ 10227ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 10237ecc28bcSPeter Maydell return false; \ 10247ecc28bcSPeter Maydell } \ 10257ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 10267ecc28bcSPeter Maydell } 10277ecc28bcSPeter Maydell 10287ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 10297ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 1030a26a352bSPeter Maydell 1031e4a6d4a6SPeter Maydell #define WRAP_FP_GVEC(WRAPNAME, FPST, FUNC) \ 1032e4a6d4a6SPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 1033a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 1034a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 1035a26a352bSPeter Maydell { \ 1036e4a6d4a6SPeter Maydell TCGv_ptr fpst = fpstatus_ptr(FPST); \ 1037a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 1038a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 1039a26a352bSPeter Maydell tcg_temp_free_ptr(fpst); \ 1040e4a6d4a6SPeter Maydell } 1041e4a6d4a6SPeter Maydell 1042e4a6d4a6SPeter Maydell #define DO_3S_FP_GVEC(INSN,SFUNC,HFUNC) \ 1043e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp32_3s, FPST_STD, SFUNC) \ 1044e4a6d4a6SPeter Maydell WRAP_FP_GVEC(gen_##INSN##_fp16_3s, FPST_STD_F16, HFUNC) \ 1045a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1046a26a352bSPeter Maydell { \ 10476cf0f240SPeter Maydell if (a->size == MO_16) { \ 1048e4a6d4a6SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1049a26a352bSPeter Maydell return false; \ 1050a26a352bSPeter Maydell } \ 1051e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp16_3s); \ 1052e4a6d4a6SPeter Maydell } \ 1053e4a6d4a6SPeter Maydell return do_3same(s, a, gen_##INSN##_fp32_3s); \ 1054a26a352bSPeter Maydell } 1055a26a352bSPeter Maydell 1056a26a352bSPeter Maydell 1057e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s, gen_helper_gvec_fadd_h) 1058e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s, gen_helper_gvec_fsub_h) 1059e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s, gen_helper_gvec_fabd_h) 1060e4a6d4a6SPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s, gen_helper_gvec_fmul_h) 1061ad505db2SPeter Maydell DO_3S_FP_GVEC(VCEQ, gen_helper_gvec_fceq_s, gen_helper_gvec_fceq_h) 1062ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGE, gen_helper_gvec_fcge_s, gen_helper_gvec_fcge_h) 1063ad505db2SPeter Maydell DO_3S_FP_GVEC(VCGT, gen_helper_gvec_fcgt_s, gen_helper_gvec_fcgt_h) 1064bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGE, gen_helper_gvec_facge_s, gen_helper_gvec_facge_h) 1065bb2741daSPeter Maydell DO_3S_FP_GVEC(VACGT, gen_helper_gvec_facgt_s, gen_helper_gvec_facgt_h) 1066e43268c5SPeter Maydell DO_3S_FP_GVEC(VMAX, gen_helper_gvec_fmax_s, gen_helper_gvec_fmax_h) 1067e43268c5SPeter Maydell DO_3S_FP_GVEC(VMIN, gen_helper_gvec_fmin_s, gen_helper_gvec_fmin_h) 1068e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLA, gen_helper_gvec_fmla_s, gen_helper_gvec_fmla_h) 1069e5adc706SPeter Maydell DO_3S_FP_GVEC(VMLS, gen_helper_gvec_fmls_s, gen_helper_gvec_fmls_h) 1070cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMA, gen_helper_gvec_vfma_s, gen_helper_gvec_vfma_h) 1071cf722d75SPeter Maydell DO_3S_FP_GVEC(VFMS, gen_helper_gvec_vfms_s, gen_helper_gvec_vfms_h) 1072ac8c62c4SPeter Maydell DO_3S_FP_GVEC(VRECPS, gen_helper_gvec_recps_nf_s, gen_helper_gvec_recps_nf_h) 107340fde72dSPeter Maydell DO_3S_FP_GVEC(VRSQRTS, gen_helper_gvec_rsqrts_nf_s, gen_helper_gvec_rsqrts_nf_h) 1074ab978335SPeter Maydell 1075e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp32_3s, FPST_STD, gen_helper_gvec_fmaxnum_s) 1076e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMAXNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fmaxnum_h) 1077e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp32_3s, FPST_STD, gen_helper_gvec_fminnum_s) 1078e22705bbSPeter Maydell WRAP_FP_GVEC(gen_VMINNM_fp16_3s, FPST_STD_F16, gen_helper_gvec_fminnum_h) 1079e22705bbSPeter Maydell 1080d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1081d5fdf9e9SPeter Maydell { 1082d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1083d5fdf9e9SPeter Maydell return false; 1084d5fdf9e9SPeter Maydell } 1085d5fdf9e9SPeter Maydell 10866cf0f240SPeter Maydell if (a->size == MO_16) { 1087e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1088d5fdf9e9SPeter Maydell return false; 1089d5fdf9e9SPeter Maydell } 1090e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp16_3s); 1091e22705bbSPeter Maydell } 1092e22705bbSPeter Maydell return do_3same(s, a, gen_VMAXNM_fp32_3s); 1093d5fdf9e9SPeter Maydell } 1094d5fdf9e9SPeter Maydell 1095d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1096d5fdf9e9SPeter Maydell { 1097d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1098d5fdf9e9SPeter Maydell return false; 1099d5fdf9e9SPeter Maydell } 1100d5fdf9e9SPeter Maydell 11016cf0f240SPeter Maydell if (a->size == MO_16) { 1102e22705bbSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 1103d5fdf9e9SPeter Maydell return false; 1104d5fdf9e9SPeter Maydell } 1105e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp16_3s); 1106e22705bbSPeter Maydell } 1107e22705bbSPeter Maydell return do_3same(s, a, gen_VMINNM_fp32_3s); 1108d5fdf9e9SPeter Maydell } 1109d5fdf9e9SPeter Maydell 11101dc587eeSPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, 11111dc587eeSPeter Maydell gen_helper_gvec_3_ptr *fn) 1112ab978335SPeter Maydell { 11131dc587eeSPeter Maydell /* FP pairwise operations */ 1114ab978335SPeter Maydell TCGv_ptr fpstatus; 1115ab978335SPeter Maydell 1116ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1117ab978335SPeter Maydell return false; 1118ab978335SPeter Maydell } 1119ab978335SPeter Maydell 1120ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1121ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1122ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1123ab978335SPeter Maydell return false; 1124ab978335SPeter Maydell } 1125ab978335SPeter Maydell 1126ab978335SPeter Maydell if (!vfp_access_check(s)) { 1127ab978335SPeter Maydell return true; 1128ab978335SPeter Maydell } 1129ab978335SPeter Maydell 1130ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1131ab978335SPeter Maydell 1132ab978335SPeter Maydell 11336cf0f240SPeter Maydell fpstatus = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 11341dc587eeSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 11351dc587eeSPeter Maydell vfp_reg_offset(1, a->vn), 11361dc587eeSPeter Maydell vfp_reg_offset(1, a->vm), 11371dc587eeSPeter Maydell fpstatus, 8, 8, 0, fn); 1138ab978335SPeter Maydell tcg_temp_free_ptr(fpstatus); 1139ab978335SPeter Maydell 1140ab978335SPeter Maydell return true; 1141ab978335SPeter Maydell } 1142ab978335SPeter Maydell 1143ab978335SPeter Maydell /* 1144ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1145ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1146ab978335SPeter Maydell */ 1147ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1148ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1149ab978335SPeter Maydell { \ 11506cf0f240SPeter Maydell if (a->size == MO_16) { \ 11511dc587eeSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 1152ab978335SPeter Maydell return false; \ 1153ab978335SPeter Maydell } \ 11541dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##h); \ 11551dc587eeSPeter Maydell } \ 11561dc587eeSPeter Maydell return do_3same_fp_pair(s, a, FUNC##s); \ 1157ab978335SPeter Maydell } 1158ab978335SPeter Maydell 11591dc587eeSPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_neon_padd) 11601dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_neon_pmax) 11611dc587eeSPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_neon_pmin) 1162d3c8c736SPeter Maydell 1163d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1164d3c8c736SPeter Maydell { 1165d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1166d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1167015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1168015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 1169d3c8c736SPeter Maydell 1170d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1171d3c8c736SPeter Maydell return false; 1172d3c8c736SPeter Maydell } 1173d3c8c736SPeter Maydell 1174d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1175d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1176d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1177d3c8c736SPeter Maydell return false; 1178d3c8c736SPeter Maydell } 1179d3c8c736SPeter Maydell 1180d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1181d3c8c736SPeter Maydell return false; 1182d3c8c736SPeter Maydell } 1183d3c8c736SPeter Maydell 1184d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1185d3c8c736SPeter Maydell return true; 1186d3c8c736SPeter Maydell } 1187d3c8c736SPeter Maydell 1188d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1189d3c8c736SPeter Maydell return true; 1190d3c8c736SPeter Maydell } 1191d3c8c736SPeter Maydell 1192d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1193d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1194d3c8c736SPeter Maydell { \ 1195d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1196d3c8c736SPeter Maydell } \ 1197d3c8c736SPeter Maydell 1198d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1199d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1200434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1201434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1202434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1203434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1204434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1205434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1206434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 120766432d6bSPeter Maydell 120866432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 120966432d6bSPeter Maydell { 121066432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 121166432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 121266432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 121366432d6bSPeter Maydell } 121466432d6bSPeter Maydell 121566432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 121666432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 121766432d6bSPeter Maydell { 121866432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 121966432d6bSPeter Maydell } 122066432d6bSPeter Maydell 122166432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 122266432d6bSPeter Maydell { 122366432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 122466432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 122566432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 122666432d6bSPeter Maydell } else { 122766432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 122866432d6bSPeter Maydell } 122966432d6bSPeter Maydell } 123037bfce81SPeter Maydell 123137bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 123237bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 123337bfce81SPeter Maydell { 123437bfce81SPeter Maydell /* 123537bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 123637bfce81SPeter Maydell * function needs to be passed cpu_env. 123737bfce81SPeter Maydell */ 123837bfce81SPeter Maydell TCGv_i64 constimm; 123937bfce81SPeter Maydell int pass; 124037bfce81SPeter Maydell 124137bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 124237bfce81SPeter Maydell return false; 124337bfce81SPeter Maydell } 124437bfce81SPeter Maydell 124537bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 124637bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 124737bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 124837bfce81SPeter Maydell return false; 124937bfce81SPeter Maydell } 125037bfce81SPeter Maydell 125137bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 125237bfce81SPeter Maydell return false; 125337bfce81SPeter Maydell } 125437bfce81SPeter Maydell 125537bfce81SPeter Maydell if (!vfp_access_check(s)) { 125637bfce81SPeter Maydell return true; 125737bfce81SPeter Maydell } 125837bfce81SPeter Maydell 125937bfce81SPeter Maydell /* 126037bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 126137bfce81SPeter Maydell * by immediate using the variable shift operations. 126237bfce81SPeter Maydell */ 126337bfce81SPeter Maydell constimm = tcg_const_i64(dup_const(a->size, a->shift)); 126437bfce81SPeter Maydell 126537bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 126637bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 126737bfce81SPeter Maydell 12680aa8e700SRichard Henderson read_neon_element64(tmp, a->vm, pass, MO_64); 126937bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 12700aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, pass, MO_64); 1271a4f67e18SPeter Maydell tcg_temp_free_i64(tmp); 127237bfce81SPeter Maydell } 127337bfce81SPeter Maydell tcg_temp_free_i64(constimm); 127437bfce81SPeter Maydell return true; 127537bfce81SPeter Maydell } 127637bfce81SPeter Maydell 127737bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 127837bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 127937bfce81SPeter Maydell { 128037bfce81SPeter Maydell /* 128137bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 128237bfce81SPeter Maydell * helper needs to be passed cpu_env. 128337bfce81SPeter Maydell */ 1284a712266fSRichard Henderson TCGv_i32 constimm, tmp; 128537bfce81SPeter Maydell int pass; 128637bfce81SPeter Maydell 128737bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 128837bfce81SPeter Maydell return false; 128937bfce81SPeter Maydell } 129037bfce81SPeter Maydell 129137bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 129237bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 129337bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 129437bfce81SPeter Maydell return false; 129537bfce81SPeter Maydell } 129637bfce81SPeter Maydell 129737bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 129837bfce81SPeter Maydell return false; 129937bfce81SPeter Maydell } 130037bfce81SPeter Maydell 130137bfce81SPeter Maydell if (!vfp_access_check(s)) { 130237bfce81SPeter Maydell return true; 130337bfce81SPeter Maydell } 130437bfce81SPeter Maydell 130537bfce81SPeter Maydell /* 130637bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 130737bfce81SPeter Maydell * by immediate using the variable shift operations. 130837bfce81SPeter Maydell */ 130937bfce81SPeter Maydell constimm = tcg_const_i32(dup_const(a->size, a->shift)); 1310a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 131137bfce81SPeter Maydell 131237bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 1313a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 131437bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 1315a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 131637bfce81SPeter Maydell } 1317a712266fSRichard Henderson tcg_temp_free_i32(tmp); 131837bfce81SPeter Maydell tcg_temp_free_i32(constimm); 131937bfce81SPeter Maydell return true; 132037bfce81SPeter Maydell } 132137bfce81SPeter Maydell 132237bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 132337bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 132437bfce81SPeter Maydell { \ 132537bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 132637bfce81SPeter Maydell } \ 132737bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 132837bfce81SPeter Maydell { \ 132937bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 133037bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 133137bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 133237bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 133337bfce81SPeter Maydell }; \ 133437bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 133537bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 133637bfce81SPeter Maydell } 133737bfce81SPeter Maydell 133837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 133937bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 134037bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1341712182d3SPeter Maydell 1342712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1343712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1344712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1345712182d3SPeter Maydell { 1346712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1347712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1348712182d3SPeter Maydell TCGv_i32 rd; 1349712182d3SPeter Maydell 1350712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1351712182d3SPeter Maydell return false; 1352712182d3SPeter Maydell } 1353712182d3SPeter Maydell 1354712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1355712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1356712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1357712182d3SPeter Maydell return false; 1358712182d3SPeter Maydell } 1359712182d3SPeter Maydell 1360712182d3SPeter Maydell if (a->vm & 1) { 1361712182d3SPeter Maydell return false; 1362712182d3SPeter Maydell } 1363712182d3SPeter Maydell 1364712182d3SPeter Maydell if (!vfp_access_check(s)) { 1365712182d3SPeter Maydell return true; 1366712182d3SPeter Maydell } 1367712182d3SPeter Maydell 1368712182d3SPeter Maydell /* 1369712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1370712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1371712182d3SPeter Maydell */ 1372712182d3SPeter Maydell constimm = tcg_const_i64(-a->shift); 1373712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1374712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1375a712266fSRichard Henderson rd = tcg_temp_new_i32(); 1376712182d3SPeter Maydell 1377712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 13780aa8e700SRichard Henderson read_neon_element64(rm1, a->vm, 0, MO_64); 13790aa8e700SRichard Henderson read_neon_element64(rm2, a->vm, 1, MO_64); 1380712182d3SPeter Maydell 1381712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1382712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1383a712266fSRichard Henderson write_neon_element32(rd, a->vd, 0, MO_32); 1384712182d3SPeter Maydell 1385712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1386712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1387a712266fSRichard Henderson write_neon_element32(rd, a->vd, 1, MO_32); 1388712182d3SPeter Maydell 1389a712266fSRichard Henderson tcg_temp_free_i32(rd); 1390712182d3SPeter Maydell tcg_temp_free_i64(rm1); 1391712182d3SPeter Maydell tcg_temp_free_i64(rm2); 1392712182d3SPeter Maydell tcg_temp_free_i64(constimm); 1393712182d3SPeter Maydell 1394712182d3SPeter Maydell return true; 1395712182d3SPeter Maydell } 1396712182d3SPeter Maydell 1397712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1398712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1399712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1400712182d3SPeter Maydell { 1401712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1402712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1403712182d3SPeter Maydell TCGv_i64 rtmp; 1404712182d3SPeter Maydell uint32_t imm; 1405712182d3SPeter Maydell 1406712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1407712182d3SPeter Maydell return false; 1408712182d3SPeter Maydell } 1409712182d3SPeter Maydell 1410712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1411712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1412712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1413712182d3SPeter Maydell return false; 1414712182d3SPeter Maydell } 1415712182d3SPeter Maydell 1416712182d3SPeter Maydell if (a->vm & 1) { 1417712182d3SPeter Maydell return false; 1418712182d3SPeter Maydell } 1419712182d3SPeter Maydell 1420712182d3SPeter Maydell if (!vfp_access_check(s)) { 1421712182d3SPeter Maydell return true; 1422712182d3SPeter Maydell } 1423712182d3SPeter Maydell 1424712182d3SPeter Maydell /* 1425712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1426712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1427712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1428712182d3SPeter Maydell */ 1429712182d3SPeter Maydell if (a->size == 1) { 1430712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1431712182d3SPeter Maydell imm |= imm << 16; 1432712182d3SPeter Maydell } else { 1433712182d3SPeter Maydell /* size == 2 */ 1434712182d3SPeter Maydell imm = -a->shift; 1435712182d3SPeter Maydell } 1436712182d3SPeter Maydell constimm = tcg_const_i32(imm); 1437712182d3SPeter Maydell 1438712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1439a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1440a712266fSRichard Henderson rm2 = tcg_temp_new_i32(); 1441a712266fSRichard Henderson rm3 = tcg_temp_new_i32(); 1442a712266fSRichard Henderson rm4 = tcg_temp_new_i32(); 1443a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 0, MO_32); 1444a712266fSRichard Henderson read_neon_element32(rm2, a->vm, 1, MO_32); 1445a712266fSRichard Henderson read_neon_element32(rm3, a->vm, 2, MO_32); 1446a712266fSRichard Henderson read_neon_element32(rm4, a->vm, 3, MO_32); 1447712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1448712182d3SPeter Maydell 1449712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1450712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1451712182d3SPeter Maydell 1452712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1453712182d3SPeter Maydell tcg_temp_free_i32(rm2); 1454712182d3SPeter Maydell 1455712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1456a712266fSRichard Henderson write_neon_element32(rm1, a->vd, 0, MO_32); 1457a712266fSRichard Henderson tcg_temp_free_i32(rm1); 1458712182d3SPeter Maydell 1459712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1460712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1461712182d3SPeter Maydell tcg_temp_free_i32(constimm); 1462712182d3SPeter Maydell 1463712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1464712182d3SPeter Maydell tcg_temp_free_i32(rm4); 1465712182d3SPeter Maydell 1466712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1467712182d3SPeter Maydell tcg_temp_free_i64(rtmp); 1468a712266fSRichard Henderson write_neon_element32(rm3, a->vd, 1, MO_32); 1469a712266fSRichard Henderson tcg_temp_free_i32(rm3); 1470712182d3SPeter Maydell return true; 1471712182d3SPeter Maydell } 1472712182d3SPeter Maydell 1473712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1474712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1475712182d3SPeter Maydell { \ 1476712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1477712182d3SPeter Maydell } 1478712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1479712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1480712182d3SPeter Maydell { \ 1481712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1482712182d3SPeter Maydell } 1483712182d3SPeter Maydell 1484712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1485712182d3SPeter Maydell { 1486712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1487712182d3SPeter Maydell } 1488712182d3SPeter Maydell 1489712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1490712182d3SPeter Maydell { 1491712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1492712182d3SPeter Maydell } 1493712182d3SPeter Maydell 1494712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1495712182d3SPeter Maydell { 1496712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1497712182d3SPeter Maydell } 1498712182d3SPeter Maydell 1499712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1500712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1501712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1502712182d3SPeter Maydell 1503712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1504712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1505712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1506712182d3SPeter Maydell 1507712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1508712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1509712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1510712182d3SPeter Maydell 1511712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1512712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1513712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1514b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1515b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1516b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1517b4a3a77bSPeter Maydell 1518b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1519b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1520b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1521b4a3a77bSPeter Maydell 1522b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1523b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1524b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1525b4a3a77bSPeter Maydell 1526b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1527b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1528b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1529968bf842SPeter Maydell 1530968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1531968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1532968bf842SPeter Maydell { 1533968bf842SPeter Maydell TCGv_i64 tmp; 1534968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1535968bf842SPeter Maydell uint64_t widen_mask = 0; 1536968bf842SPeter Maydell 1537968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1538968bf842SPeter Maydell return false; 1539968bf842SPeter Maydell } 1540968bf842SPeter Maydell 1541968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1542968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1543968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1544968bf842SPeter Maydell return false; 1545968bf842SPeter Maydell } 1546968bf842SPeter Maydell 1547968bf842SPeter Maydell if (a->vd & 1) { 1548968bf842SPeter Maydell return false; 1549968bf842SPeter Maydell } 1550968bf842SPeter Maydell 1551968bf842SPeter Maydell if (!vfp_access_check(s)) { 1552968bf842SPeter Maydell return true; 1553968bf842SPeter Maydell } 1554968bf842SPeter Maydell 1555968bf842SPeter Maydell /* 1556968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1557968bf842SPeter Maydell * than the width of the source type, so after widening the input 1558968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1559968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1560968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1561968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1562968bf842SPeter Maydell */ 1563968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1564968bf842SPeter Maydell int esize = 8 << a->size; 1565968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1566968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1567968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1568968bf842SPeter Maydell } 1569968bf842SPeter Maydell 1570a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 1571a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 1572a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 1573a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 1574968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1575968bf842SPeter Maydell 1576968bf842SPeter Maydell widenfn(tmp, rm0); 15779593a398SPeter Maydell tcg_temp_free_i32(rm0); 1578968bf842SPeter Maydell if (a->shift != 0) { 1579968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1580968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1581968bf842SPeter Maydell } 15820aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 0, MO_64); 1583968bf842SPeter Maydell 1584968bf842SPeter Maydell widenfn(tmp, rm1); 15859593a398SPeter Maydell tcg_temp_free_i32(rm1); 1586968bf842SPeter Maydell if (a->shift != 0) { 1587968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1588968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1589968bf842SPeter Maydell } 15900aa8e700SRichard Henderson write_neon_element64(tmp, a->vd, 1, MO_64); 1591968bf842SPeter Maydell tcg_temp_free_i64(tmp); 1592968bf842SPeter Maydell return true; 1593968bf842SPeter Maydell } 1594968bf842SPeter Maydell 1595968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1596968bf842SPeter Maydell { 1597448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1598968bf842SPeter Maydell gen_helper_neon_widen_s8, 1599968bf842SPeter Maydell gen_helper_neon_widen_s16, 1600968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1601968bf842SPeter Maydell }; 1602968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1603968bf842SPeter Maydell } 1604968bf842SPeter Maydell 1605968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1606968bf842SPeter Maydell { 1607448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1608968bf842SPeter Maydell gen_helper_neon_widen_u8, 1609968bf842SPeter Maydell gen_helper_neon_widen_u16, 1610968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1611968bf842SPeter Maydell }; 1612968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1613968bf842SPeter Maydell } 16143da26f11SPeter Maydell 16153da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 16167b959c58SPeter Maydell gen_helper_gvec_2_ptr *fn) 16173da26f11SPeter Maydell { 16183da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 16197b959c58SPeter Maydell int vec_size = a->q ? 16 : 8; 1620015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 1621015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 16227b959c58SPeter Maydell TCGv_ptr fpst; 16233da26f11SPeter Maydell 16243da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 16253da26f11SPeter Maydell return false; 16263da26f11SPeter Maydell } 16273da26f11SPeter Maydell 16280ae715c6SPeter Maydell if (a->size == MO_16) { 16297b959c58SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 16307b959c58SPeter Maydell return false; 16317b959c58SPeter Maydell } 16327b959c58SPeter Maydell } 16337b959c58SPeter Maydell 16343da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 16353da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 16363da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 16373da26f11SPeter Maydell return false; 16383da26f11SPeter Maydell } 16393da26f11SPeter Maydell 16403da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 16413da26f11SPeter Maydell return false; 16423da26f11SPeter Maydell } 16433da26f11SPeter Maydell 16443da26f11SPeter Maydell if (!vfp_access_check(s)) { 16453da26f11SPeter Maydell return true; 16463da26f11SPeter Maydell } 16473da26f11SPeter Maydell 16480ae715c6SPeter Maydell fpst = fpstatus_ptr(a->size == MO_16 ? FPST_STD_F16 : FPST_STD); 16497b959c58SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, vec_size, vec_size, a->shift, fn); 16507b959c58SPeter Maydell tcg_temp_free_ptr(fpst); 16513da26f11SPeter Maydell return true; 16523da26f11SPeter Maydell } 16533da26f11SPeter Maydell 16543da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 16553da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 16563da26f11SPeter Maydell { \ 16573da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 16583da26f11SPeter Maydell } 16593da26f11SPeter Maydell 16607b959c58SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_gvec_vcvt_sf) 16617b959c58SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_gvec_vcvt_uf) 16627b959c58SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_gvec_vcvt_fs) 16637b959c58SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_gvec_vcvt_fu) 16642c35a39eSPeter Maydell 166524018cf3SPeter Maydell DO_FP_2SH(VCVT_SH, gen_helper_gvec_vcvt_sh) 166624018cf3SPeter Maydell DO_FP_2SH(VCVT_UH, gen_helper_gvec_vcvt_uh) 166724018cf3SPeter Maydell DO_FP_2SH(VCVT_HS, gen_helper_gvec_vcvt_hs) 166824018cf3SPeter Maydell DO_FP_2SH(VCVT_HU, gen_helper_gvec_vcvt_hu) 166924018cf3SPeter Maydell 16702c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) 16712c35a39eSPeter Maydell { 16722c35a39eSPeter Maydell /* 16732c35a39eSPeter Maydell * Expand the encoded constant. 16742c35a39eSPeter Maydell * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. 16752c35a39eSPeter Maydell * We choose to not special-case this and will behave as if a 16762c35a39eSPeter Maydell * valid constant encoding of 0 had been given. 16772c35a39eSPeter Maydell * cmode = 15 op = 1 must UNDEF; we assume decode has handled that. 16782c35a39eSPeter Maydell */ 16792c35a39eSPeter Maydell switch (cmode) { 16802c35a39eSPeter Maydell case 0: case 1: 16812c35a39eSPeter Maydell /* no-op */ 16822c35a39eSPeter Maydell break; 16832c35a39eSPeter Maydell case 2: case 3: 16842c35a39eSPeter Maydell imm <<= 8; 16852c35a39eSPeter Maydell break; 16862c35a39eSPeter Maydell case 4: case 5: 16872c35a39eSPeter Maydell imm <<= 16; 16882c35a39eSPeter Maydell break; 16892c35a39eSPeter Maydell case 6: case 7: 16902c35a39eSPeter Maydell imm <<= 24; 16912c35a39eSPeter Maydell break; 16922c35a39eSPeter Maydell case 8: case 9: 16932c35a39eSPeter Maydell imm |= imm << 16; 16942c35a39eSPeter Maydell break; 16952c35a39eSPeter Maydell case 10: case 11: 16962c35a39eSPeter Maydell imm = (imm << 8) | (imm << 24); 16972c35a39eSPeter Maydell break; 16982c35a39eSPeter Maydell case 12: 16992c35a39eSPeter Maydell imm = (imm << 8) | 0xff; 17002c35a39eSPeter Maydell break; 17012c35a39eSPeter Maydell case 13: 17022c35a39eSPeter Maydell imm = (imm << 16) | 0xffff; 17032c35a39eSPeter Maydell break; 17042c35a39eSPeter Maydell case 14: 17052c35a39eSPeter Maydell if (op) { 17062c35a39eSPeter Maydell /* 17072c35a39eSPeter Maydell * This is the only case where the top and bottom 32 bits 17082c35a39eSPeter Maydell * of the encoded constant differ. 17092c35a39eSPeter Maydell */ 17102c35a39eSPeter Maydell uint64_t imm64 = 0; 17112c35a39eSPeter Maydell int n; 17122c35a39eSPeter Maydell 17132c35a39eSPeter Maydell for (n = 0; n < 8; n++) { 17142c35a39eSPeter Maydell if (imm & (1 << n)) { 17152c35a39eSPeter Maydell imm64 |= (0xffULL << (n * 8)); 17162c35a39eSPeter Maydell } 17172c35a39eSPeter Maydell } 17182c35a39eSPeter Maydell return imm64; 17192c35a39eSPeter Maydell } 17202c35a39eSPeter Maydell imm |= (imm << 8) | (imm << 16) | (imm << 24); 17212c35a39eSPeter Maydell break; 17222c35a39eSPeter Maydell case 15: 17232c35a39eSPeter Maydell imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) 17242c35a39eSPeter Maydell | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); 17252c35a39eSPeter Maydell break; 17262c35a39eSPeter Maydell } 17272c35a39eSPeter Maydell if (op) { 17282c35a39eSPeter Maydell imm = ~imm; 17292c35a39eSPeter Maydell } 17302c35a39eSPeter Maydell return dup_const(MO_32, imm); 17312c35a39eSPeter Maydell } 17322c35a39eSPeter Maydell 17332c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 17342c35a39eSPeter Maydell GVecGen2iFn *fn) 17352c35a39eSPeter Maydell { 17362c35a39eSPeter Maydell uint64_t imm; 17372c35a39eSPeter Maydell int reg_ofs, vec_size; 17382c35a39eSPeter Maydell 17392c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17402c35a39eSPeter Maydell return false; 17412c35a39eSPeter Maydell } 17422c35a39eSPeter Maydell 17432c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17442c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 17452c35a39eSPeter Maydell return false; 17462c35a39eSPeter Maydell } 17472c35a39eSPeter Maydell 17482c35a39eSPeter Maydell if (a->vd & a->q) { 17492c35a39eSPeter Maydell return false; 17502c35a39eSPeter Maydell } 17512c35a39eSPeter Maydell 17522c35a39eSPeter Maydell if (!vfp_access_check(s)) { 17532c35a39eSPeter Maydell return true; 17542c35a39eSPeter Maydell } 17552c35a39eSPeter Maydell 1756015ee81aSRichard Henderson reg_ofs = neon_full_reg_offset(a->vd); 17572c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 17582c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 17592c35a39eSPeter Maydell 17602c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 17612c35a39eSPeter Maydell return true; 17622c35a39eSPeter Maydell } 17632c35a39eSPeter Maydell 17642c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 17652c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 17662c35a39eSPeter Maydell { 17672c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 17682c35a39eSPeter Maydell } 17692c35a39eSPeter Maydell 17702c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 17712c35a39eSPeter Maydell { 17722c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 17732c35a39eSPeter Maydell GVecGen2iFn *fn; 17742c35a39eSPeter Maydell 17752c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 17762c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 17772c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 17782c35a39eSPeter Maydell } else { 17792c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 17802c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 17812c35a39eSPeter Maydell return false; 17822c35a39eSPeter Maydell } 17832c35a39eSPeter Maydell fn = gen_VMOV_1r; 17842c35a39eSPeter Maydell } 17852c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 17862c35a39eSPeter Maydell } 1787b28be095SPeter Maydell 1788b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1789b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1790b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 17918aab18a2SRichard Henderson int src1_mop, int src2_mop) 1792b28be095SPeter Maydell { 1793b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1794b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1795b28be095SPeter Maydell 1796b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1797b28be095SPeter Maydell return false; 1798b28be095SPeter Maydell } 1799b28be095SPeter Maydell 1800b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1801b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1802b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1803b28be095SPeter Maydell return false; 1804b28be095SPeter Maydell } 1805b28be095SPeter Maydell 18068aab18a2SRichard Henderson if (!opfn) { 1807b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1808b28be095SPeter Maydell return false; 1809b28be095SPeter Maydell } 1810b28be095SPeter Maydell 18118aab18a2SRichard Henderson if ((a->vd & 1) || (src1_mop == MO_Q && (a->vn & 1))) { 1812b28be095SPeter Maydell return false; 1813b28be095SPeter Maydell } 1814b28be095SPeter Maydell 1815b28be095SPeter Maydell if (!vfp_access_check(s)) { 1816b28be095SPeter Maydell return true; 1817b28be095SPeter Maydell } 1818b28be095SPeter Maydell 1819b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1820b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1821b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1822b28be095SPeter Maydell 18238aab18a2SRichard Henderson if (src1_mop >= 0) { 18248aab18a2SRichard Henderson read_neon_element64(rn0_64, a->vn, 0, src1_mop); 1825b28be095SPeter Maydell } else { 1826a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1827a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 0, MO_32); 1828b28be095SPeter Maydell widenfn(rn0_64, tmp); 1829b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1830b28be095SPeter Maydell } 18318aab18a2SRichard Henderson if (src2_mop >= 0) { 18328aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 0, src2_mop); 18338aab18a2SRichard Henderson } else { 18348aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18358aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 18368aab18a2SRichard Henderson widenfn(rm_64, tmp); 18378aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 18388aab18a2SRichard Henderson } 1839b28be095SPeter Maydell 1840b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1841b28be095SPeter Maydell 1842b28be095SPeter Maydell /* 1843b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1844b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1845b28be095SPeter Maydell */ 18468aab18a2SRichard Henderson if (src1_mop >= 0) { 18478aab18a2SRichard Henderson read_neon_element64(rn1_64, a->vn, 1, src1_mop); 1848b28be095SPeter Maydell } else { 1849a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1850a712266fSRichard Henderson read_neon_element32(tmp, a->vn, 1, MO_32); 1851b28be095SPeter Maydell widenfn(rn1_64, tmp); 1852b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1853b28be095SPeter Maydell } 18548aab18a2SRichard Henderson if (src2_mop >= 0) { 18558aab18a2SRichard Henderson read_neon_element64(rm_64, a->vm, 1, src2_mop); 18568aab18a2SRichard Henderson } else { 18578aab18a2SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 18588aab18a2SRichard Henderson read_neon_element32(tmp, a->vm, 1, MO_32); 18598aab18a2SRichard Henderson widenfn(rm_64, tmp); 18608aab18a2SRichard Henderson tcg_temp_free_i32(tmp); 18618aab18a2SRichard Henderson } 1862b28be095SPeter Maydell 18630aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 1864b28be095SPeter Maydell 1865b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 18660aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 1867b28be095SPeter Maydell 1868b28be095SPeter Maydell tcg_temp_free_i64(rn0_64); 1869b28be095SPeter Maydell tcg_temp_free_i64(rn1_64); 1870b28be095SPeter Maydell tcg_temp_free_i64(rm_64); 1871b28be095SPeter Maydell 1872b28be095SPeter Maydell return true; 1873b28be095SPeter Maydell } 1874b28be095SPeter Maydell 18758aab18a2SRichard Henderson #define DO_PREWIDEN(INSN, S, OP, SRC1WIDE, SIGN) \ 1876b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1877b28be095SPeter Maydell { \ 1878b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1879b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1880b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 18818aab18a2SRichard Henderson NULL, NULL, \ 1882b28be095SPeter Maydell }; \ 1883b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1884b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1885b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1886b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1887b28be095SPeter Maydell NULL, \ 1888b28be095SPeter Maydell }; \ 18898aab18a2SRichard Henderson int narrow_mop = a->size == MO_32 ? MO_32 | SIGN : -1; \ 18908aab18a2SRichard Henderson return do_prewiden_3d(s, a, widenfn[a->size], addfn[a->size], \ 18918aab18a2SRichard Henderson SRC1WIDE ? MO_Q : narrow_mop, \ 18928aab18a2SRichard Henderson narrow_mop); \ 1893b28be095SPeter Maydell } 1894b28be095SPeter Maydell 18958aab18a2SRichard Henderson DO_PREWIDEN(VADDL_S, s, add, false, MO_SIGN) 18968aab18a2SRichard Henderson DO_PREWIDEN(VADDL_U, u, add, false, 0) 18978aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_S, s, sub, false, MO_SIGN) 18988aab18a2SRichard Henderson DO_PREWIDEN(VSUBL_U, u, sub, false, 0) 18998aab18a2SRichard Henderson DO_PREWIDEN(VADDW_S, s, add, true, MO_SIGN) 19008aab18a2SRichard Henderson DO_PREWIDEN(VADDW_U, u, add, true, 0) 19018aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_S, s, sub, true, MO_SIGN) 19028aab18a2SRichard Henderson DO_PREWIDEN(VSUBW_U, u, sub, true, 0) 19030fa1ab03SPeter Maydell 19040fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 19050fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 19060fa1ab03SPeter Maydell { 19070fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 19080fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 19090fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 19100fa1ab03SPeter Maydell 19110fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 19120fa1ab03SPeter Maydell return false; 19130fa1ab03SPeter Maydell } 19140fa1ab03SPeter Maydell 19150fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 19160fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 19170fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 19180fa1ab03SPeter Maydell return false; 19190fa1ab03SPeter Maydell } 19200fa1ab03SPeter Maydell 19210fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 19220fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 19230fa1ab03SPeter Maydell return false; 19240fa1ab03SPeter Maydell } 19250fa1ab03SPeter Maydell 19260fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 19270fa1ab03SPeter Maydell return false; 19280fa1ab03SPeter Maydell } 19290fa1ab03SPeter Maydell 19300fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 19310fa1ab03SPeter Maydell return true; 19320fa1ab03SPeter Maydell } 19330fa1ab03SPeter Maydell 19340fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 19350fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 19360fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 19370fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 19380fa1ab03SPeter Maydell 19390aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 0, MO_64); 19400aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 0, MO_64); 19410fa1ab03SPeter Maydell 19420fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19430fa1ab03SPeter Maydell 19440fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 19450fa1ab03SPeter Maydell 19460aa8e700SRichard Henderson read_neon_element64(rn_64, a->vn, 1, MO_64); 19470aa8e700SRichard Henderson read_neon_element64(rm_64, a->vm, 1, MO_64); 19480fa1ab03SPeter Maydell 19490fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19500fa1ab03SPeter Maydell 19510fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 19520fa1ab03SPeter Maydell 1953a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 1954a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 19550fa1ab03SPeter Maydell 1956a712266fSRichard Henderson tcg_temp_free_i32(rd0); 1957a712266fSRichard Henderson tcg_temp_free_i32(rd1); 19580fa1ab03SPeter Maydell tcg_temp_free_i64(rn_64); 19590fa1ab03SPeter Maydell tcg_temp_free_i64(rm_64); 19600fa1ab03SPeter Maydell 19610fa1ab03SPeter Maydell return true; 19620fa1ab03SPeter Maydell } 19630fa1ab03SPeter Maydell 19640fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 19650fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 19660fa1ab03SPeter Maydell { \ 19670fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 19680fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 19690fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 19700fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 19710fa1ab03SPeter Maydell NULL, \ 19720fa1ab03SPeter Maydell }; \ 19730fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 19740fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 19750fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 19760fa1ab03SPeter Maydell EXTOP, \ 19770fa1ab03SPeter Maydell NULL, \ 19780fa1ab03SPeter Maydell }; \ 19790fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 19800fa1ab03SPeter Maydell } 19810fa1ab03SPeter Maydell 19820fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 19830fa1ab03SPeter Maydell { 19840fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 19850fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 19860fa1ab03SPeter Maydell } 19870fa1ab03SPeter Maydell 19880fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 19890fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 19900fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 19910fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 1992f5b28401SPeter Maydell 1993f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 1994f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 1995f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 1996f5b28401SPeter Maydell { 1997f5b28401SPeter Maydell /* 1998f5b28401SPeter Maydell * 3-regs different lengths, long operations. 1999f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 2000f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 2001f5b28401SPeter Maydell * that result into the double-width destination. 2002f5b28401SPeter Maydell */ 2003f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 2004f5b28401SPeter Maydell TCGv_i32 rn, rm; 2005f5b28401SPeter Maydell 2006f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2007f5b28401SPeter Maydell return false; 2008f5b28401SPeter Maydell } 2009f5b28401SPeter Maydell 2010f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2011f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2012f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2013f5b28401SPeter Maydell return false; 2014f5b28401SPeter Maydell } 2015f5b28401SPeter Maydell 2016f5b28401SPeter Maydell if (!opfn) { 2017f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 2018f5b28401SPeter Maydell return false; 2019f5b28401SPeter Maydell } 2020f5b28401SPeter Maydell 2021f5b28401SPeter Maydell if (a->vd & 1) { 2022f5b28401SPeter Maydell return false; 2023f5b28401SPeter Maydell } 2024f5b28401SPeter Maydell 2025f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2026f5b28401SPeter Maydell return true; 2027f5b28401SPeter Maydell } 2028f5b28401SPeter Maydell 2029f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2030f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2031f5b28401SPeter Maydell 2032a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2033a712266fSRichard Henderson rm = tcg_temp_new_i32(); 2034a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 2035a712266fSRichard Henderson read_neon_element32(rm, a->vm, 0, MO_32); 2036f5b28401SPeter Maydell opfn(rd0, rn, rm); 2037f5b28401SPeter Maydell 2038a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 2039a712266fSRichard Henderson read_neon_element32(rm, a->vm, 1, MO_32); 2040f5b28401SPeter Maydell opfn(rd1, rn, rm); 2041f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2042f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2043f5b28401SPeter Maydell 2044f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2045f5b28401SPeter Maydell if (accfn) { 2046f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 20470aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 0, MO_64); 20489f1a5f93SRichard Henderson accfn(rd0, tmp, rd0); 20490aa8e700SRichard Henderson read_neon_element64(tmp, a->vd, 1, MO_64); 20509f1a5f93SRichard Henderson accfn(rd1, tmp, rd1); 2051f5b28401SPeter Maydell tcg_temp_free_i64(tmp); 2052f5b28401SPeter Maydell } 2053f5b28401SPeter Maydell 20549f1a5f93SRichard Henderson write_neon_element64(rd0, a->vd, 0, MO_64); 20559f1a5f93SRichard Henderson write_neon_element64(rd1, a->vd, 1, MO_64); 2056f5b28401SPeter Maydell tcg_temp_free_i64(rd0); 2057f5b28401SPeter Maydell tcg_temp_free_i64(rd1); 2058f5b28401SPeter Maydell 2059f5b28401SPeter Maydell return true; 2060f5b28401SPeter Maydell } 2061f5b28401SPeter Maydell 2062f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2063f5b28401SPeter Maydell { 2064f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2065f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2066f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2067f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2068f5b28401SPeter Maydell NULL, 2069f5b28401SPeter Maydell }; 2070f5b28401SPeter Maydell 2071f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2072f5b28401SPeter Maydell } 2073f5b28401SPeter Maydell 2074f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2075f5b28401SPeter Maydell { 2076f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2077f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2078f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2079f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2080f5b28401SPeter Maydell NULL, 2081f5b28401SPeter Maydell }; 2082f5b28401SPeter Maydell 2083f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2084f5b28401SPeter Maydell } 2085f5b28401SPeter Maydell 2086f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2087f5b28401SPeter Maydell { 2088f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2089f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2090f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2091f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2092f5b28401SPeter Maydell NULL, 2093f5b28401SPeter Maydell }; 2094f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2095f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2096f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2097f5b28401SPeter Maydell tcg_gen_add_i64, 2098f5b28401SPeter Maydell NULL, 2099f5b28401SPeter Maydell }; 2100f5b28401SPeter Maydell 2101f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2102f5b28401SPeter Maydell } 2103f5b28401SPeter Maydell 2104f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2105f5b28401SPeter Maydell { 2106f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2107f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2108f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2109f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2110f5b28401SPeter Maydell NULL, 2111f5b28401SPeter Maydell }; 2112f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2113f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2114f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2115f5b28401SPeter Maydell tcg_gen_add_i64, 2116f5b28401SPeter Maydell NULL, 2117f5b28401SPeter Maydell }; 2118f5b28401SPeter Maydell 2119f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2120f5b28401SPeter Maydell } 21213a1d9eb0SPeter Maydell 21223a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21233a1d9eb0SPeter Maydell { 21243a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21253a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21263a1d9eb0SPeter Maydell 21273a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 21283a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21293a1d9eb0SPeter Maydell 21303a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21313a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21323a1d9eb0SPeter Maydell } 21333a1d9eb0SPeter Maydell 21343a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21353a1d9eb0SPeter Maydell { 21363a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21373a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21383a1d9eb0SPeter Maydell 21393a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 21403a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21413a1d9eb0SPeter Maydell 21423a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21433a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21443a1d9eb0SPeter Maydell } 21453a1d9eb0SPeter Maydell 21463a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 21473a1d9eb0SPeter Maydell { 21483a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21493a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 21503a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 21513a1d9eb0SPeter Maydell gen_mull_s32, 21523a1d9eb0SPeter Maydell NULL, 21533a1d9eb0SPeter Maydell }; 21543a1d9eb0SPeter Maydell 21553a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21563a1d9eb0SPeter Maydell } 21573a1d9eb0SPeter Maydell 21583a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 21593a1d9eb0SPeter Maydell { 21603a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21613a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 21623a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 21633a1d9eb0SPeter Maydell gen_mull_u32, 21643a1d9eb0SPeter Maydell NULL, 21653a1d9eb0SPeter Maydell }; 21663a1d9eb0SPeter Maydell 21673a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21683a1d9eb0SPeter Maydell } 21693a1d9eb0SPeter Maydell 21703a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 21713a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 21723a1d9eb0SPeter Maydell { \ 21733a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 21743a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 21753a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 21763a1d9eb0SPeter Maydell gen_##MULL##32, \ 21773a1d9eb0SPeter Maydell NULL, \ 21783a1d9eb0SPeter Maydell }; \ 21793a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 21803a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 21813a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 21823a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 21833a1d9eb0SPeter Maydell NULL, \ 21843a1d9eb0SPeter Maydell }; \ 21853a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 21863a1d9eb0SPeter Maydell } 21873a1d9eb0SPeter Maydell 21883a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 21893a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 21903a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 21913a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 21929546ca59SPeter Maydell 21939546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21949546ca59SPeter Maydell { 21959546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 21969546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 21979546ca59SPeter Maydell } 21989546ca59SPeter Maydell 21999546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22009546ca59SPeter Maydell { 22019546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 22029546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 22039546ca59SPeter Maydell } 22049546ca59SPeter Maydell 22059546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 22069546ca59SPeter Maydell { 22079546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22089546ca59SPeter Maydell NULL, 22099546ca59SPeter Maydell gen_VQDMULL_16, 22109546ca59SPeter Maydell gen_VQDMULL_32, 22119546ca59SPeter Maydell NULL, 22129546ca59SPeter Maydell }; 22139546ca59SPeter Maydell 22149546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22159546ca59SPeter Maydell } 22169546ca59SPeter Maydell 22179546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22189546ca59SPeter Maydell { 22199546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22209546ca59SPeter Maydell } 22219546ca59SPeter Maydell 22229546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22239546ca59SPeter Maydell { 22249546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22259546ca59SPeter Maydell } 22269546ca59SPeter Maydell 22279546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 22289546ca59SPeter Maydell { 22299546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22309546ca59SPeter Maydell NULL, 22319546ca59SPeter Maydell gen_VQDMULL_16, 22329546ca59SPeter Maydell gen_VQDMULL_32, 22339546ca59SPeter Maydell NULL, 22349546ca59SPeter Maydell }; 22359546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22369546ca59SPeter Maydell NULL, 22379546ca59SPeter Maydell gen_VQDMLAL_acc_16, 22389546ca59SPeter Maydell gen_VQDMLAL_acc_32, 22399546ca59SPeter Maydell NULL, 22409546ca59SPeter Maydell }; 22419546ca59SPeter Maydell 22429546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22439546ca59SPeter Maydell } 22449546ca59SPeter Maydell 22459546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22469546ca59SPeter Maydell { 22479546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 22489546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22499546ca59SPeter Maydell } 22509546ca59SPeter Maydell 22519546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22529546ca59SPeter Maydell { 22539546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 22549546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22559546ca59SPeter Maydell } 22569546ca59SPeter Maydell 22579546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 22589546ca59SPeter Maydell { 22599546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22609546ca59SPeter Maydell NULL, 22619546ca59SPeter Maydell gen_VQDMULL_16, 22629546ca59SPeter Maydell gen_VQDMULL_32, 22639546ca59SPeter Maydell NULL, 22649546ca59SPeter Maydell }; 22659546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22669546ca59SPeter Maydell NULL, 22679546ca59SPeter Maydell gen_VQDMLSL_acc_16, 22689546ca59SPeter Maydell gen_VQDMLSL_acc_32, 22699546ca59SPeter Maydell NULL, 22709546ca59SPeter Maydell }; 22719546ca59SPeter Maydell 22729546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22739546ca59SPeter Maydell } 227418fb58d5SPeter Maydell 227518fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 227618fb58d5SPeter Maydell { 227718fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 227818fb58d5SPeter Maydell 227918fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 228018fb58d5SPeter Maydell return false; 228118fb58d5SPeter Maydell } 228218fb58d5SPeter Maydell 228318fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 228418fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 228518fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 228618fb58d5SPeter Maydell return false; 228718fb58d5SPeter Maydell } 228818fb58d5SPeter Maydell 228918fb58d5SPeter Maydell if (a->vd & 1) { 229018fb58d5SPeter Maydell return false; 229118fb58d5SPeter Maydell } 229218fb58d5SPeter Maydell 229318fb58d5SPeter Maydell switch (a->size) { 229418fb58d5SPeter Maydell case 0: 229518fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 229618fb58d5SPeter Maydell break; 229718fb58d5SPeter Maydell case 2: 229818fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 229918fb58d5SPeter Maydell return false; 230018fb58d5SPeter Maydell } 230118fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 230218fb58d5SPeter Maydell break; 230318fb58d5SPeter Maydell default: 230418fb58d5SPeter Maydell return false; 230518fb58d5SPeter Maydell } 230618fb58d5SPeter Maydell 230718fb58d5SPeter Maydell if (!vfp_access_check(s)) { 230818fb58d5SPeter Maydell return true; 230918fb58d5SPeter Maydell } 231018fb58d5SPeter Maydell 2311015ee81aSRichard Henderson tcg_gen_gvec_3_ool(neon_full_reg_offset(a->vd), 2312015ee81aSRichard Henderson neon_full_reg_offset(a->vn), 2313015ee81aSRichard Henderson neon_full_reg_offset(a->vm), 231418fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 231518fb58d5SPeter Maydell return true; 231618fb58d5SPeter Maydell } 231796fc80f5SPeter Maydell 231896fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 231996fc80f5SPeter Maydell { 232096fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 232196fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 232296fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 232396fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 232496fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 232596fc80f5SPeter Maydell } 232696fc80f5SPeter Maydell 232796fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 232896fc80f5SPeter Maydell { 232996fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 233096fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 233196fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 233296fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 233396fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 233496fc80f5SPeter Maydell } 233596fc80f5SPeter Maydell 233696fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 233796fc80f5SPeter Maydell { 2338a712266fSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 2339a712266fSRichard Henderson if (size == MO_16) { 2340a712266fSRichard Henderson read_neon_element32(tmp, reg & 7, reg >> 4, MO_32); 234196fc80f5SPeter Maydell if (reg & 8) { 234296fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 234396fc80f5SPeter Maydell } else { 234496fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 234596fc80f5SPeter Maydell } 234696fc80f5SPeter Maydell } else { 2347a712266fSRichard Henderson read_neon_element32(tmp, reg & 15, reg >> 4, MO_32); 234896fc80f5SPeter Maydell } 234996fc80f5SPeter Maydell return tmp; 235096fc80f5SPeter Maydell } 235196fc80f5SPeter Maydell 235296fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 235396fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 235496fc80f5SPeter Maydell { 235596fc80f5SPeter Maydell /* 235696fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 235796fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 235896fc80f5SPeter Maydell * perform an accumulation operation of that result into the 235996fc80f5SPeter Maydell * destination. 236096fc80f5SPeter Maydell */ 2361a712266fSRichard Henderson TCGv_i32 scalar, tmp; 236296fc80f5SPeter Maydell int pass; 236396fc80f5SPeter Maydell 236496fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 236596fc80f5SPeter Maydell return false; 236696fc80f5SPeter Maydell } 236796fc80f5SPeter Maydell 236896fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 236996fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 237096fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 237196fc80f5SPeter Maydell return false; 237296fc80f5SPeter Maydell } 237396fc80f5SPeter Maydell 237496fc80f5SPeter Maydell if (!opfn) { 237596fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 237696fc80f5SPeter Maydell return false; 237796fc80f5SPeter Maydell } 237896fc80f5SPeter Maydell 237996fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 238096fc80f5SPeter Maydell return false; 238196fc80f5SPeter Maydell } 238296fc80f5SPeter Maydell 238396fc80f5SPeter Maydell if (!vfp_access_check(s)) { 238496fc80f5SPeter Maydell return true; 238596fc80f5SPeter Maydell } 238696fc80f5SPeter Maydell 238796fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2388a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 238996fc80f5SPeter Maydell 239096fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2391a712266fSRichard Henderson read_neon_element32(tmp, a->vn, pass, MO_32); 239296fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 239396fc80f5SPeter Maydell if (accfn) { 2394a712266fSRichard Henderson TCGv_i32 rd = tcg_temp_new_i32(); 2395a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 239696fc80f5SPeter Maydell accfn(tmp, rd, tmp); 239796fc80f5SPeter Maydell tcg_temp_free_i32(rd); 239896fc80f5SPeter Maydell } 2399a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 240096fc80f5SPeter Maydell } 2401a712266fSRichard Henderson tcg_temp_free_i32(tmp); 240296fc80f5SPeter Maydell tcg_temp_free_i32(scalar); 240396fc80f5SPeter Maydell return true; 240496fc80f5SPeter Maydell } 240596fc80f5SPeter Maydell 240696fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 240796fc80f5SPeter Maydell { 240896fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 240996fc80f5SPeter Maydell NULL, 241096fc80f5SPeter Maydell gen_helper_neon_mul_u16, 241196fc80f5SPeter Maydell tcg_gen_mul_i32, 241296fc80f5SPeter Maydell NULL, 241396fc80f5SPeter Maydell }; 241496fc80f5SPeter Maydell 241596fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 241696fc80f5SPeter Maydell } 241796fc80f5SPeter Maydell 241896fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 241996fc80f5SPeter Maydell { 242096fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 242196fc80f5SPeter Maydell NULL, 242296fc80f5SPeter Maydell gen_helper_neon_mul_u16, 242396fc80f5SPeter Maydell tcg_gen_mul_i32, 242496fc80f5SPeter Maydell NULL, 242596fc80f5SPeter Maydell }; 242696fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 242796fc80f5SPeter Maydell NULL, 242896fc80f5SPeter Maydell gen_helper_neon_add_u16, 242996fc80f5SPeter Maydell tcg_gen_add_i32, 243096fc80f5SPeter Maydell NULL, 243196fc80f5SPeter Maydell }; 243296fc80f5SPeter Maydell 243396fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 243496fc80f5SPeter Maydell } 243596fc80f5SPeter Maydell 243696fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 243796fc80f5SPeter Maydell { 243896fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 243996fc80f5SPeter Maydell NULL, 244096fc80f5SPeter Maydell gen_helper_neon_mul_u16, 244196fc80f5SPeter Maydell tcg_gen_mul_i32, 244296fc80f5SPeter Maydell NULL, 244396fc80f5SPeter Maydell }; 244496fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 244596fc80f5SPeter Maydell NULL, 244696fc80f5SPeter Maydell gen_helper_neon_sub_u16, 244796fc80f5SPeter Maydell tcg_gen_sub_i32, 244896fc80f5SPeter Maydell NULL, 244996fc80f5SPeter Maydell }; 245096fc80f5SPeter Maydell 245196fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 245296fc80f5SPeter Maydell } 245385ac9aefSPeter Maydell 2454fc8ae790SPeter Maydell static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, 2455fc8ae790SPeter Maydell gen_helper_gvec_3_ptr *fn) 2456fc8ae790SPeter Maydell { 2457fc8ae790SPeter Maydell /* Two registers and a scalar, using gvec */ 2458fc8ae790SPeter Maydell int vec_size = a->q ? 16 : 8; 2459015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 2460015ee81aSRichard Henderson int rn_ofs = neon_full_reg_offset(a->vn); 2461fc8ae790SPeter Maydell int rm_ofs; 2462fc8ae790SPeter Maydell int idx; 2463fc8ae790SPeter Maydell TCGv_ptr fpstatus; 2464fc8ae790SPeter Maydell 2465fc8ae790SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2466fc8ae790SPeter Maydell return false; 2467fc8ae790SPeter Maydell } 2468fc8ae790SPeter Maydell 2469fc8ae790SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2470fc8ae790SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2471fc8ae790SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2472fc8ae790SPeter Maydell return false; 2473fc8ae790SPeter Maydell } 2474fc8ae790SPeter Maydell 2475fc8ae790SPeter Maydell if (!fn) { 2476fc8ae790SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2477fc8ae790SPeter Maydell return false; 2478fc8ae790SPeter Maydell } 2479fc8ae790SPeter Maydell 2480fc8ae790SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2481fc8ae790SPeter Maydell return false; 2482fc8ae790SPeter Maydell } 2483fc8ae790SPeter Maydell 2484fc8ae790SPeter Maydell if (!vfp_access_check(s)) { 2485fc8ae790SPeter Maydell return true; 2486fc8ae790SPeter Maydell } 2487fc8ae790SPeter Maydell 2488fc8ae790SPeter Maydell /* a->vm is M:Vm, which encodes both register and index */ 2489fc8ae790SPeter Maydell idx = extract32(a->vm, a->size + 2, 2); 2490fc8ae790SPeter Maydell a->vm = extract32(a->vm, 0, a->size + 2); 2491015ee81aSRichard Henderson rm_ofs = neon_full_reg_offset(a->vm); 2492fc8ae790SPeter Maydell 2493fc8ae790SPeter Maydell fpstatus = fpstatus_ptr(a->size == 1 ? FPST_STD_F16 : FPST_STD); 2494fc8ae790SPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpstatus, 2495fc8ae790SPeter Maydell vec_size, vec_size, idx, fn); 2496fc8ae790SPeter Maydell tcg_temp_free_ptr(fpstatus); 2497fc8ae790SPeter Maydell return true; 2498fc8ae790SPeter Maydell } 2499fc8ae790SPeter Maydell 2500fc8ae790SPeter Maydell #define DO_VMUL_F_2sc(NAME, FUNC) \ 2501fc8ae790SPeter Maydell static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \ 250285ac9aefSPeter Maydell { \ 2503fc8ae790SPeter Maydell static gen_helper_gvec_3_ptr * const opfn[] = { \ 2504fc8ae790SPeter Maydell NULL, \ 2505fc8ae790SPeter Maydell gen_helper_##FUNC##_h, \ 2506fc8ae790SPeter Maydell gen_helper_##FUNC##_s, \ 2507fc8ae790SPeter Maydell NULL, \ 2508fc8ae790SPeter Maydell }; \ 2509fc8ae790SPeter Maydell if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \ 2510fc8ae790SPeter Maydell return false; \ 2511fc8ae790SPeter Maydell } \ 2512fc8ae790SPeter Maydell return do_2scalar_fp_vec(s, a, opfn[a->size]); \ 251385ac9aefSPeter Maydell } 251485ac9aefSPeter Maydell 2515fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMUL, gvec_fmul_idx) 2516fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx) 2517fc8ae790SPeter Maydell DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx) 2518b2fc7be9SPeter Maydell 2519b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2520b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2521b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2522b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2523b2fc7be9SPeter Maydell 2524b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2525b2fc7be9SPeter Maydell { 2526b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2527b2fc7be9SPeter Maydell NULL, 2528b2fc7be9SPeter Maydell gen_VQDMULH_16, 2529b2fc7be9SPeter Maydell gen_VQDMULH_32, 2530b2fc7be9SPeter Maydell NULL, 2531b2fc7be9SPeter Maydell }; 2532b2fc7be9SPeter Maydell 2533b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2534b2fc7be9SPeter Maydell } 2535b2fc7be9SPeter Maydell 2536b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2537b2fc7be9SPeter Maydell { 2538b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2539b2fc7be9SPeter Maydell NULL, 2540b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2541b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2542b2fc7be9SPeter Maydell NULL, 2543b2fc7be9SPeter Maydell }; 2544b2fc7be9SPeter Maydell 2545b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2546b2fc7be9SPeter Maydell } 2547aa318f5bSPeter Maydell 2548aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2549aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2550aa318f5bSPeter Maydell { 2551aa318f5bSPeter Maydell /* 2552aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2553aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2554aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2555aa318f5bSPeter Maydell */ 2556a712266fSRichard Henderson TCGv_i32 scalar, rn, rd; 2557aa318f5bSPeter Maydell int pass; 2558aa318f5bSPeter Maydell 2559aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2560aa318f5bSPeter Maydell return false; 2561aa318f5bSPeter Maydell } 2562aa318f5bSPeter Maydell 2563aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2564aa318f5bSPeter Maydell return false; 2565aa318f5bSPeter Maydell } 2566aa318f5bSPeter Maydell 2567aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2568aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2569aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2570aa318f5bSPeter Maydell return false; 2571aa318f5bSPeter Maydell } 2572aa318f5bSPeter Maydell 2573aa318f5bSPeter Maydell if (!opfn) { 2574aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2575aa318f5bSPeter Maydell return false; 2576aa318f5bSPeter Maydell } 2577aa318f5bSPeter Maydell 2578aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2579aa318f5bSPeter Maydell return false; 2580aa318f5bSPeter Maydell } 2581aa318f5bSPeter Maydell 2582aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2583aa318f5bSPeter Maydell return true; 2584aa318f5bSPeter Maydell } 2585aa318f5bSPeter Maydell 2586aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2587a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2588a712266fSRichard Henderson rd = tcg_temp_new_i32(); 2589aa318f5bSPeter Maydell 2590aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2591a712266fSRichard Henderson read_neon_element32(rn, a->vn, pass, MO_32); 2592a712266fSRichard Henderson read_neon_element32(rd, a->vd, pass, MO_32); 2593aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2594a712266fSRichard Henderson write_neon_element32(rd, a->vd, pass, MO_32); 2595aa318f5bSPeter Maydell } 2596a712266fSRichard Henderson tcg_temp_free_i32(rn); 2597a712266fSRichard Henderson tcg_temp_free_i32(rd); 2598aa318f5bSPeter Maydell tcg_temp_free_i32(scalar); 2599aa318f5bSPeter Maydell 2600aa318f5bSPeter Maydell return true; 2601aa318f5bSPeter Maydell } 2602aa318f5bSPeter Maydell 2603aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2604aa318f5bSPeter Maydell { 2605aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2606aa318f5bSPeter Maydell NULL, 2607aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2608aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2609aa318f5bSPeter Maydell NULL, 2610aa318f5bSPeter Maydell }; 2611aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2612aa318f5bSPeter Maydell } 2613aa318f5bSPeter Maydell 2614aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2615aa318f5bSPeter Maydell { 2616aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2617aa318f5bSPeter Maydell NULL, 2618aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2619aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2620aa318f5bSPeter Maydell NULL, 2621aa318f5bSPeter Maydell }; 2622aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2623aa318f5bSPeter Maydell } 262477e576a9SPeter Maydell 262577e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 262677e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 262777e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 262877e576a9SPeter Maydell { 262977e576a9SPeter Maydell /* 263077e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 263177e576a9SPeter Maydell * operation on the input elements and the scalar which produces 263277e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 263377e576a9SPeter Maydell * operation of that result into the destination. 263477e576a9SPeter Maydell */ 263577e576a9SPeter Maydell TCGv_i32 scalar, rn; 263677e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 263777e576a9SPeter Maydell 263877e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 263977e576a9SPeter Maydell return false; 264077e576a9SPeter Maydell } 264177e576a9SPeter Maydell 264277e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 264377e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 264477e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 264577e576a9SPeter Maydell return false; 264677e576a9SPeter Maydell } 264777e576a9SPeter Maydell 264877e576a9SPeter Maydell if (!opfn) { 264977e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 265077e576a9SPeter Maydell return false; 265177e576a9SPeter Maydell } 265277e576a9SPeter Maydell 265377e576a9SPeter Maydell if (a->vd & 1) { 265477e576a9SPeter Maydell return false; 265577e576a9SPeter Maydell } 265677e576a9SPeter Maydell 265777e576a9SPeter Maydell if (!vfp_access_check(s)) { 265877e576a9SPeter Maydell return true; 265977e576a9SPeter Maydell } 266077e576a9SPeter Maydell 266177e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 266277e576a9SPeter Maydell 266377e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 2664a712266fSRichard Henderson rn = tcg_temp_new_i32(); 2665a712266fSRichard Henderson read_neon_element32(rn, a->vn, 0, MO_32); 266677e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 266777e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 266877e576a9SPeter Maydell 2669a712266fSRichard Henderson read_neon_element32(rn, a->vn, 1, MO_32); 267077e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 267177e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 267277e576a9SPeter Maydell tcg_temp_free_i32(rn); 267377e576a9SPeter Maydell tcg_temp_free_i32(scalar); 267477e576a9SPeter Maydell 267577e576a9SPeter Maydell if (accfn) { 267677e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 26770aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 0, MO_64); 26789f1a5f93SRichard Henderson accfn(rn0_64, t64, rn0_64); 26790aa8e700SRichard Henderson read_neon_element64(t64, a->vd, 1, MO_64); 26809f1a5f93SRichard Henderson accfn(rn1_64, t64, rn1_64); 268177e576a9SPeter Maydell tcg_temp_free_i64(t64); 26829f1a5f93SRichard Henderson } 26839f1a5f93SRichard Henderson 26840aa8e700SRichard Henderson write_neon_element64(rn0_64, a->vd, 0, MO_64); 26850aa8e700SRichard Henderson write_neon_element64(rn1_64, a->vd, 1, MO_64); 268677e576a9SPeter Maydell tcg_temp_free_i64(rn0_64); 268777e576a9SPeter Maydell tcg_temp_free_i64(rn1_64); 268877e576a9SPeter Maydell return true; 268977e576a9SPeter Maydell } 269077e576a9SPeter Maydell 269177e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 269277e576a9SPeter Maydell { 269377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 269477e576a9SPeter Maydell NULL, 269577e576a9SPeter Maydell gen_helper_neon_mull_s16, 269677e576a9SPeter Maydell gen_mull_s32, 269777e576a9SPeter Maydell NULL, 269877e576a9SPeter Maydell }; 269977e576a9SPeter Maydell 270077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 270177e576a9SPeter Maydell } 270277e576a9SPeter Maydell 270377e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 270477e576a9SPeter Maydell { 270577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 270677e576a9SPeter Maydell NULL, 270777e576a9SPeter Maydell gen_helper_neon_mull_u16, 270877e576a9SPeter Maydell gen_mull_u32, 270977e576a9SPeter Maydell NULL, 271077e576a9SPeter Maydell }; 271177e576a9SPeter Maydell 271277e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 271377e576a9SPeter Maydell } 271477e576a9SPeter Maydell 271577e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 271677e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 271777e576a9SPeter Maydell { \ 271877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 271977e576a9SPeter Maydell NULL, \ 272077e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 272177e576a9SPeter Maydell gen_##MULL##32, \ 272277e576a9SPeter Maydell NULL, \ 272377e576a9SPeter Maydell }; \ 272477e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 272577e576a9SPeter Maydell NULL, \ 272677e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 272777e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 272877e576a9SPeter Maydell NULL, \ 272977e576a9SPeter Maydell }; \ 273077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 273177e576a9SPeter Maydell } 273277e576a9SPeter Maydell 273377e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 273477e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 273577e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 273677e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 273777e576a9SPeter Maydell 273877e576a9SPeter Maydell static bool trans_VQDMULL_2sc(DisasContext *s, arg_2scalar *a) 273977e576a9SPeter Maydell { 274077e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 274177e576a9SPeter Maydell NULL, 274277e576a9SPeter Maydell gen_VQDMULL_16, 274377e576a9SPeter Maydell gen_VQDMULL_32, 274477e576a9SPeter Maydell NULL, 274577e576a9SPeter Maydell }; 274677e576a9SPeter Maydell 274777e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 274877e576a9SPeter Maydell } 274977e576a9SPeter Maydell 275077e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 275177e576a9SPeter Maydell { 275277e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 275377e576a9SPeter Maydell NULL, 275477e576a9SPeter Maydell gen_VQDMULL_16, 275577e576a9SPeter Maydell gen_VQDMULL_32, 275677e576a9SPeter Maydell NULL, 275777e576a9SPeter Maydell }; 275877e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 275977e576a9SPeter Maydell NULL, 276077e576a9SPeter Maydell gen_VQDMLAL_acc_16, 276177e576a9SPeter Maydell gen_VQDMLAL_acc_32, 276277e576a9SPeter Maydell NULL, 276377e576a9SPeter Maydell }; 276477e576a9SPeter Maydell 276577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 276677e576a9SPeter Maydell } 276777e576a9SPeter Maydell 276877e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 276977e576a9SPeter Maydell { 277077e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 277177e576a9SPeter Maydell NULL, 277277e576a9SPeter Maydell gen_VQDMULL_16, 277377e576a9SPeter Maydell gen_VQDMULL_32, 277477e576a9SPeter Maydell NULL, 277577e576a9SPeter Maydell }; 277677e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 277777e576a9SPeter Maydell NULL, 277877e576a9SPeter Maydell gen_VQDMLSL_acc_16, 277977e576a9SPeter Maydell gen_VQDMLSL_acc_32, 278077e576a9SPeter Maydell NULL, 278177e576a9SPeter Maydell }; 278277e576a9SPeter Maydell 278377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 278477e576a9SPeter Maydell } 27850aad761fSPeter Maydell 27860aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 27870aad761fSPeter Maydell { 27880aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 27890aad761fSPeter Maydell return false; 27900aad761fSPeter Maydell } 27910aad761fSPeter Maydell 27920aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 27930aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 27940aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 27950aad761fSPeter Maydell return false; 27960aad761fSPeter Maydell } 27970aad761fSPeter Maydell 27980aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 27990aad761fSPeter Maydell return false; 28000aad761fSPeter Maydell } 28010aad761fSPeter Maydell 28020aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 28030aad761fSPeter Maydell return false; 28040aad761fSPeter Maydell } 28050aad761fSPeter Maydell 28060aad761fSPeter Maydell if (!vfp_access_check(s)) { 28070aad761fSPeter Maydell return true; 28080aad761fSPeter Maydell } 28090aad761fSPeter Maydell 28100aad761fSPeter Maydell if (!a->q) { 28110aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 28120aad761fSPeter Maydell TCGv_i64 left, right, dest; 28130aad761fSPeter Maydell 28140aad761fSPeter Maydell left = tcg_temp_new_i64(); 28150aad761fSPeter Maydell right = tcg_temp_new_i64(); 28160aad761fSPeter Maydell dest = tcg_temp_new_i64(); 28170aad761fSPeter Maydell 28180aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 28190aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 28200aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 28210aa8e700SRichard Henderson write_neon_element64(dest, a->vd, 0, MO_64); 28220aad761fSPeter Maydell 28230aad761fSPeter Maydell tcg_temp_free_i64(left); 28240aad761fSPeter Maydell tcg_temp_free_i64(right); 28250aad761fSPeter Maydell tcg_temp_free_i64(dest); 28260aad761fSPeter Maydell } else { 28270aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 28280aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 28290aad761fSPeter Maydell 28300aad761fSPeter Maydell left = tcg_temp_new_i64(); 28310aad761fSPeter Maydell middle = tcg_temp_new_i64(); 28320aad761fSPeter Maydell right = tcg_temp_new_i64(); 28330aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 28340aad761fSPeter Maydell destright = tcg_temp_new_i64(); 28350aad761fSPeter Maydell 28360aad761fSPeter Maydell if (a->imm < 8) { 28370aa8e700SRichard Henderson read_neon_element64(right, a->vn, 0, MO_64); 28380aa8e700SRichard Henderson read_neon_element64(middle, a->vn, 1, MO_64); 28390aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 28400aa8e700SRichard Henderson read_neon_element64(left, a->vm, 0, MO_64); 28410aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 28420aad761fSPeter Maydell } else { 28430aa8e700SRichard Henderson read_neon_element64(right, a->vn, 1, MO_64); 28440aa8e700SRichard Henderson read_neon_element64(middle, a->vm, 0, MO_64); 28450aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 28460aa8e700SRichard Henderson read_neon_element64(left, a->vm, 1, MO_64); 28470aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 28480aad761fSPeter Maydell } 28490aad761fSPeter Maydell 28500aa8e700SRichard Henderson write_neon_element64(destright, a->vd, 0, MO_64); 28510aa8e700SRichard Henderson write_neon_element64(destleft, a->vd, 1, MO_64); 28520aad761fSPeter Maydell 28530aad761fSPeter Maydell tcg_temp_free_i64(destright); 28540aad761fSPeter Maydell tcg_temp_free_i64(destleft); 28550aad761fSPeter Maydell tcg_temp_free_i64(right); 28560aad761fSPeter Maydell tcg_temp_free_i64(middle); 28570aad761fSPeter Maydell tcg_temp_free_i64(left); 28580aad761fSPeter Maydell } 28590aad761fSPeter Maydell return true; 28600aad761fSPeter Maydell } 286154e96c74SPeter Maydell 286254e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 286354e96c74SPeter Maydell { 2864604cef3eSRichard Henderson TCGv_i64 val, def; 2865604cef3eSRichard Henderson TCGv_i32 desc; 286654e96c74SPeter Maydell 286754e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 286854e96c74SPeter Maydell return false; 286954e96c74SPeter Maydell } 287054e96c74SPeter Maydell 287154e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 287254e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 287354e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 287454e96c74SPeter Maydell return false; 287554e96c74SPeter Maydell } 287654e96c74SPeter Maydell 2877604cef3eSRichard Henderson if ((a->vn + a->len + 1) > 32) { 287854e96c74SPeter Maydell /* 287954e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 288054e96c74SPeter Maydell * helper function running off the end of the register file. 288154e96c74SPeter Maydell */ 288254e96c74SPeter Maydell return false; 288354e96c74SPeter Maydell } 2884a712266fSRichard Henderson 2885b6c56c8aSPeter Maydell if (!vfp_access_check(s)) { 2886b6c56c8aSPeter Maydell return true; 2887b6c56c8aSPeter Maydell } 2888b6c56c8aSPeter Maydell 2889604cef3eSRichard Henderson desc = tcg_const_i32((a->vn << 2) | a->len); 2890604cef3eSRichard Henderson def = tcg_temp_new_i64(); 289154e96c74SPeter Maydell if (a->op) { 2892604cef3eSRichard Henderson read_neon_element64(def, a->vd, 0, MO_64); 289354e96c74SPeter Maydell } else { 2894604cef3eSRichard Henderson tcg_gen_movi_i64(def, 0); 289554e96c74SPeter Maydell } 2896604cef3eSRichard Henderson val = tcg_temp_new_i64(); 2897604cef3eSRichard Henderson read_neon_element64(val, a->vm, 0, MO_64); 2898a712266fSRichard Henderson 2899604cef3eSRichard Henderson gen_helper_neon_tbl(val, cpu_env, desc, val, def); 2900604cef3eSRichard Henderson write_neon_element64(val, a->vd, 0, MO_64); 2901604cef3eSRichard Henderson 2902604cef3eSRichard Henderson tcg_temp_free_i64(def); 2903604cef3eSRichard Henderson tcg_temp_free_i64(val); 2904604cef3eSRichard Henderson tcg_temp_free_i32(desc); 290554e96c74SPeter Maydell return true; 290654e96c74SPeter Maydell } 29079aaa23c2SPeter Maydell 29089aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 29099aaa23c2SPeter Maydell { 29109aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 29119aaa23c2SPeter Maydell return false; 29129aaa23c2SPeter Maydell } 29139aaa23c2SPeter Maydell 29149aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 29159aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 29169aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 29179aaa23c2SPeter Maydell return false; 29189aaa23c2SPeter Maydell } 29199aaa23c2SPeter Maydell 29209aaa23c2SPeter Maydell if (a->vd & a->q) { 29219aaa23c2SPeter Maydell return false; 29229aaa23c2SPeter Maydell } 29239aaa23c2SPeter Maydell 29249aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 29259aaa23c2SPeter Maydell return true; 29269aaa23c2SPeter Maydell } 29279aaa23c2SPeter Maydell 2928015ee81aSRichard Henderson tcg_gen_gvec_dup_mem(a->size, neon_full_reg_offset(a->vd), 29299aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 29309aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 29319aaa23c2SPeter Maydell return true; 29329aaa23c2SPeter Maydell } 2933353d2b85SPeter Maydell 2934353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 2935353d2b85SPeter Maydell { 2936353d2b85SPeter Maydell int pass, half; 2937a712266fSRichard Henderson TCGv_i32 tmp[2]; 2938353d2b85SPeter Maydell 2939353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2940353d2b85SPeter Maydell return false; 2941353d2b85SPeter Maydell } 2942353d2b85SPeter Maydell 2943353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2944353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2945353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 2946353d2b85SPeter Maydell return false; 2947353d2b85SPeter Maydell } 2948353d2b85SPeter Maydell 2949353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 2950353d2b85SPeter Maydell return false; 2951353d2b85SPeter Maydell } 2952353d2b85SPeter Maydell 2953353d2b85SPeter Maydell if (a->size == 3) { 2954353d2b85SPeter Maydell return false; 2955353d2b85SPeter Maydell } 2956353d2b85SPeter Maydell 2957353d2b85SPeter Maydell if (!vfp_access_check(s)) { 2958353d2b85SPeter Maydell return true; 2959353d2b85SPeter Maydell } 2960353d2b85SPeter Maydell 2961a712266fSRichard Henderson tmp[0] = tcg_temp_new_i32(); 2962a712266fSRichard Henderson tmp[1] = tcg_temp_new_i32(); 2963353d2b85SPeter Maydell 2964a712266fSRichard Henderson for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 2965353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 2966a712266fSRichard Henderson read_neon_element32(tmp[half], a->vm, pass * 2 + half, MO_32); 2967353d2b85SPeter Maydell switch (a->size) { 2968353d2b85SPeter Maydell case 0: 2969353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 2970353d2b85SPeter Maydell break; 2971353d2b85SPeter Maydell case 1: 29728ec3de70SPeter Maydell gen_swap_half(tmp[half], tmp[half]); 2973353d2b85SPeter Maydell break; 2974353d2b85SPeter Maydell case 2: 2975353d2b85SPeter Maydell break; 2976353d2b85SPeter Maydell default: 2977353d2b85SPeter Maydell g_assert_not_reached(); 2978353d2b85SPeter Maydell } 2979353d2b85SPeter Maydell } 2980a712266fSRichard Henderson write_neon_element32(tmp[1], a->vd, pass * 2, MO_32); 2981a712266fSRichard Henderson write_neon_element32(tmp[0], a->vd, pass * 2 + 1, MO_32); 2982353d2b85SPeter Maydell } 2983a712266fSRichard Henderson 2984a712266fSRichard Henderson tcg_temp_free_i32(tmp[0]); 2985a712266fSRichard Henderson tcg_temp_free_i32(tmp[1]); 2986353d2b85SPeter Maydell return true; 2987353d2b85SPeter Maydell } 29886106af3aSPeter Maydell 29896106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 29906106af3aSPeter Maydell NeonGenWidenFn *widenfn, 29916106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 29926106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 29936106af3aSPeter Maydell { 29946106af3aSPeter Maydell /* 29956106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 29966106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 29976106af3aSPeter Maydell * into the destination with the accfn. 29986106af3aSPeter Maydell */ 29996106af3aSPeter Maydell int pass; 30006106af3aSPeter Maydell 30016106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30026106af3aSPeter Maydell return false; 30036106af3aSPeter Maydell } 30046106af3aSPeter Maydell 30056106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 30066106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 30076106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 30086106af3aSPeter Maydell return false; 30096106af3aSPeter Maydell } 30106106af3aSPeter Maydell 30116106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 30126106af3aSPeter Maydell return false; 30136106af3aSPeter Maydell } 30146106af3aSPeter Maydell 30156106af3aSPeter Maydell if (!widenfn) { 30166106af3aSPeter Maydell return false; 30176106af3aSPeter Maydell } 30186106af3aSPeter Maydell 30196106af3aSPeter Maydell if (!vfp_access_check(s)) { 30206106af3aSPeter Maydell return true; 30216106af3aSPeter Maydell } 30226106af3aSPeter Maydell 30236106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 30246106af3aSPeter Maydell TCGv_i32 tmp; 30256106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 30266106af3aSPeter Maydell 30276106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 30286106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 30296106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 3030a712266fSRichard Henderson 3031a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3032a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2, MO_32); 30336106af3aSPeter Maydell widenfn(rm0_64, tmp); 3034a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass * 2 + 1, MO_32); 30356106af3aSPeter Maydell widenfn(rm1_64, tmp); 30366106af3aSPeter Maydell tcg_temp_free_i32(tmp); 3037a712266fSRichard Henderson 30386106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 30396106af3aSPeter Maydell tcg_temp_free_i64(rm0_64); 30406106af3aSPeter Maydell tcg_temp_free_i64(rm1_64); 30416106af3aSPeter Maydell 30426106af3aSPeter Maydell if (accfn) { 30436106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 30440aa8e700SRichard Henderson read_neon_element64(tmp64, a->vd, pass, MO_64); 30456106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 30466106af3aSPeter Maydell tcg_temp_free_i64(tmp64); 30476106af3aSPeter Maydell } 30480aa8e700SRichard Henderson write_neon_element64(rd_64, a->vd, pass, MO_64); 30496106af3aSPeter Maydell tcg_temp_free_i64(rd_64); 30506106af3aSPeter Maydell } 30516106af3aSPeter Maydell return true; 30526106af3aSPeter Maydell } 30536106af3aSPeter Maydell 30546106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 30556106af3aSPeter Maydell { 30566106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30576106af3aSPeter Maydell gen_helper_neon_widen_s8, 30586106af3aSPeter Maydell gen_helper_neon_widen_s16, 30596106af3aSPeter Maydell tcg_gen_ext_i32_i64, 30606106af3aSPeter Maydell NULL, 30616106af3aSPeter Maydell }; 30626106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30636106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30646106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30656106af3aSPeter Maydell tcg_gen_add_i64, 30666106af3aSPeter Maydell NULL, 30676106af3aSPeter Maydell }; 30686106af3aSPeter Maydell 30696106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 30706106af3aSPeter Maydell } 30716106af3aSPeter Maydell 30726106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 30736106af3aSPeter Maydell { 30746106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30756106af3aSPeter Maydell gen_helper_neon_widen_u8, 30766106af3aSPeter Maydell gen_helper_neon_widen_u16, 30776106af3aSPeter Maydell tcg_gen_extu_i32_i64, 30786106af3aSPeter Maydell NULL, 30796106af3aSPeter Maydell }; 30806106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30816106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30826106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30836106af3aSPeter Maydell tcg_gen_add_i64, 30846106af3aSPeter Maydell NULL, 30856106af3aSPeter Maydell }; 30866106af3aSPeter Maydell 30876106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 30886106af3aSPeter Maydell } 30896106af3aSPeter Maydell 30906106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 30916106af3aSPeter Maydell { 30926106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30936106af3aSPeter Maydell gen_helper_neon_widen_s8, 30946106af3aSPeter Maydell gen_helper_neon_widen_s16, 30956106af3aSPeter Maydell tcg_gen_ext_i32_i64, 30966106af3aSPeter Maydell NULL, 30976106af3aSPeter Maydell }; 30986106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30996106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31006106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31016106af3aSPeter Maydell tcg_gen_add_i64, 31026106af3aSPeter Maydell NULL, 31036106af3aSPeter Maydell }; 31046106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31056106af3aSPeter Maydell gen_helper_neon_addl_u16, 31066106af3aSPeter Maydell gen_helper_neon_addl_u32, 31076106af3aSPeter Maydell tcg_gen_add_i64, 31086106af3aSPeter Maydell NULL, 31096106af3aSPeter Maydell }; 31106106af3aSPeter Maydell 31116106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31126106af3aSPeter Maydell accfn[a->size]); 31136106af3aSPeter Maydell } 31146106af3aSPeter Maydell 31156106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 31166106af3aSPeter Maydell { 31176106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31186106af3aSPeter Maydell gen_helper_neon_widen_u8, 31196106af3aSPeter Maydell gen_helper_neon_widen_u16, 31206106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31216106af3aSPeter Maydell NULL, 31226106af3aSPeter Maydell }; 31236106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31246106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31256106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31266106af3aSPeter Maydell tcg_gen_add_i64, 31276106af3aSPeter Maydell NULL, 31286106af3aSPeter Maydell }; 31296106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31306106af3aSPeter Maydell gen_helper_neon_addl_u16, 31316106af3aSPeter Maydell gen_helper_neon_addl_u32, 31326106af3aSPeter Maydell tcg_gen_add_i64, 31336106af3aSPeter Maydell NULL, 31346106af3aSPeter Maydell }; 31356106af3aSPeter Maydell 31366106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31376106af3aSPeter Maydell accfn[a->size]); 31386106af3aSPeter Maydell } 3139567663a2SPeter Maydell 3140567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3141567663a2SPeter Maydell 3142567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3143567663a2SPeter Maydell ZipFn *fn) 3144567663a2SPeter Maydell { 3145567663a2SPeter Maydell TCGv_ptr pd, pm; 3146567663a2SPeter Maydell 3147567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3148567663a2SPeter Maydell return false; 3149567663a2SPeter Maydell } 3150567663a2SPeter Maydell 3151567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3152567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3153567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3154567663a2SPeter Maydell return false; 3155567663a2SPeter Maydell } 3156567663a2SPeter Maydell 3157567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3158567663a2SPeter Maydell return false; 3159567663a2SPeter Maydell } 3160567663a2SPeter Maydell 3161567663a2SPeter Maydell if (!fn) { 3162567663a2SPeter Maydell /* Bad size or size/q combination */ 3163567663a2SPeter Maydell return false; 3164567663a2SPeter Maydell } 3165567663a2SPeter Maydell 3166567663a2SPeter Maydell if (!vfp_access_check(s)) { 3167567663a2SPeter Maydell return true; 3168567663a2SPeter Maydell } 3169567663a2SPeter Maydell 3170567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3171567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3172567663a2SPeter Maydell fn(pd, pm); 3173567663a2SPeter Maydell tcg_temp_free_ptr(pd); 3174567663a2SPeter Maydell tcg_temp_free_ptr(pm); 3175567663a2SPeter Maydell return true; 3176567663a2SPeter Maydell } 3177567663a2SPeter Maydell 3178567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3179567663a2SPeter Maydell { 3180567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3181567663a2SPeter Maydell { 3182567663a2SPeter Maydell gen_helper_neon_unzip8, 3183567663a2SPeter Maydell gen_helper_neon_unzip16, 3184567663a2SPeter Maydell NULL, 3185567663a2SPeter Maydell NULL, 3186567663a2SPeter Maydell }, { 3187567663a2SPeter Maydell gen_helper_neon_qunzip8, 3188567663a2SPeter Maydell gen_helper_neon_qunzip16, 3189567663a2SPeter Maydell gen_helper_neon_qunzip32, 3190567663a2SPeter Maydell NULL, 3191567663a2SPeter Maydell } 3192567663a2SPeter Maydell }; 3193567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3194567663a2SPeter Maydell } 3195567663a2SPeter Maydell 3196567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3197567663a2SPeter Maydell { 3198567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3199567663a2SPeter Maydell { 3200567663a2SPeter Maydell gen_helper_neon_zip8, 3201567663a2SPeter Maydell gen_helper_neon_zip16, 3202567663a2SPeter Maydell NULL, 3203567663a2SPeter Maydell NULL, 3204567663a2SPeter Maydell }, { 3205567663a2SPeter Maydell gen_helper_neon_qzip8, 3206567663a2SPeter Maydell gen_helper_neon_qzip16, 3207567663a2SPeter Maydell gen_helper_neon_qzip32, 3208567663a2SPeter Maydell NULL, 3209567663a2SPeter Maydell } 3210567663a2SPeter Maydell }; 3211567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3212567663a2SPeter Maydell } 32133882bdacSPeter Maydell 32143882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 32153882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 32163882bdacSPeter Maydell { 32173882bdacSPeter Maydell TCGv_i64 rm; 32183882bdacSPeter Maydell TCGv_i32 rd0, rd1; 32193882bdacSPeter Maydell 32203882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 32213882bdacSPeter Maydell return false; 32223882bdacSPeter Maydell } 32233882bdacSPeter Maydell 32243882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 32253882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 32263882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 32273882bdacSPeter Maydell return false; 32283882bdacSPeter Maydell } 32293882bdacSPeter Maydell 32303882bdacSPeter Maydell if (a->vm & 1) { 32313882bdacSPeter Maydell return false; 32323882bdacSPeter Maydell } 32333882bdacSPeter Maydell 32343882bdacSPeter Maydell if (!narrowfn) { 32353882bdacSPeter Maydell return false; 32363882bdacSPeter Maydell } 32373882bdacSPeter Maydell 32383882bdacSPeter Maydell if (!vfp_access_check(s)) { 32393882bdacSPeter Maydell return true; 32403882bdacSPeter Maydell } 32413882bdacSPeter Maydell 32423882bdacSPeter Maydell rm = tcg_temp_new_i64(); 32433882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 32443882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 32453882bdacSPeter Maydell 32460aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 0, MO_64); 32473882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 32480aa8e700SRichard Henderson read_neon_element64(rm, a->vm, 1, MO_64); 32493882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 3250a712266fSRichard Henderson write_neon_element32(rd0, a->vd, 0, MO_32); 3251a712266fSRichard Henderson write_neon_element32(rd1, a->vd, 1, MO_32); 3252a712266fSRichard Henderson tcg_temp_free_i32(rd0); 3253a712266fSRichard Henderson tcg_temp_free_i32(rd1); 32543882bdacSPeter Maydell tcg_temp_free_i64(rm); 32553882bdacSPeter Maydell return true; 32563882bdacSPeter Maydell } 32573882bdacSPeter Maydell 32583882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 32593882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 32603882bdacSPeter Maydell { \ 32613882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 32623882bdacSPeter Maydell FUNC##8, \ 32633882bdacSPeter Maydell FUNC##16, \ 32643882bdacSPeter Maydell FUNC##32, \ 32653882bdacSPeter Maydell NULL, \ 32663882bdacSPeter Maydell }; \ 32673882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 32683882bdacSPeter Maydell } 32693882bdacSPeter Maydell 32703882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 32713882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 32723882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 32733882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3274749e2be3SPeter Maydell 3275749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3276749e2be3SPeter Maydell { 3277749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3278749e2be3SPeter Maydell TCGv_i64 rd; 3279749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3280749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3281749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3282749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3283749e2be3SPeter Maydell NULL, 3284749e2be3SPeter Maydell }; 3285749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3286749e2be3SPeter Maydell 3287749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3288749e2be3SPeter Maydell return false; 3289749e2be3SPeter Maydell } 3290749e2be3SPeter Maydell 3291749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3292749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3293749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3294749e2be3SPeter Maydell return false; 3295749e2be3SPeter Maydell } 3296749e2be3SPeter Maydell 3297749e2be3SPeter Maydell if (a->vd & 1) { 3298749e2be3SPeter Maydell return false; 3299749e2be3SPeter Maydell } 3300749e2be3SPeter Maydell 3301749e2be3SPeter Maydell if (!widenfn) { 3302749e2be3SPeter Maydell return false; 3303749e2be3SPeter Maydell } 3304749e2be3SPeter Maydell 3305749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3306749e2be3SPeter Maydell return true; 3307749e2be3SPeter Maydell } 3308749e2be3SPeter Maydell 3309749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3310a712266fSRichard Henderson rm0 = tcg_temp_new_i32(); 3311a712266fSRichard Henderson rm1 = tcg_temp_new_i32(); 3312749e2be3SPeter Maydell 3313a712266fSRichard Henderson read_neon_element32(rm0, a->vm, 0, MO_32); 3314a712266fSRichard Henderson read_neon_element32(rm1, a->vm, 1, MO_32); 3315749e2be3SPeter Maydell 3316749e2be3SPeter Maydell widenfn(rd, rm0); 3317749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 33180aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 0, MO_64); 3319749e2be3SPeter Maydell widenfn(rd, rm1); 3320749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 33210aa8e700SRichard Henderson write_neon_element64(rd, a->vd, 1, MO_64); 3322749e2be3SPeter Maydell 3323749e2be3SPeter Maydell tcg_temp_free_i64(rd); 3324749e2be3SPeter Maydell tcg_temp_free_i32(rm0); 3325749e2be3SPeter Maydell tcg_temp_free_i32(rm1); 3326749e2be3SPeter Maydell return true; 3327749e2be3SPeter Maydell } 3328654a5173SPeter Maydell 3329654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3330654a5173SPeter Maydell { 3331654a5173SPeter Maydell TCGv_ptr fpst; 3332654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3333654a5173SPeter Maydell 3334654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3335654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3336654a5173SPeter Maydell return false; 3337654a5173SPeter Maydell } 3338654a5173SPeter Maydell 3339654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3340654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3341654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3342654a5173SPeter Maydell return false; 3343654a5173SPeter Maydell } 3344654a5173SPeter Maydell 3345654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3346654a5173SPeter Maydell return false; 3347654a5173SPeter Maydell } 3348654a5173SPeter Maydell 3349654a5173SPeter Maydell if (!vfp_access_check(s)) { 3350654a5173SPeter Maydell return true; 3351654a5173SPeter Maydell } 3352654a5173SPeter Maydell 3353a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3354654a5173SPeter Maydell ahp = get_ahp_flag(); 3355a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3356a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3357654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3358a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3359a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3360654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3361654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3362654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3363a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 2, MO_32); 3364654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3365a712266fSRichard Henderson tmp3 = tcg_temp_new_i32(); 3366a712266fSRichard Henderson read_neon_element32(tmp3, a->vm, 3, MO_32); 3367a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 0, MO_32); 3368a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3369654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3370654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3371654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3372a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 1, MO_32); 3373a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3374654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3375654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3376654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3377654a5173SPeter Maydell 3378654a5173SPeter Maydell return true; 3379654a5173SPeter Maydell } 3380654a5173SPeter Maydell 3381654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3382654a5173SPeter Maydell { 3383654a5173SPeter Maydell TCGv_ptr fpst; 3384654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3385654a5173SPeter Maydell 3386654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3387654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3388654a5173SPeter Maydell return false; 3389654a5173SPeter Maydell } 3390654a5173SPeter Maydell 3391654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3392654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3393654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3394654a5173SPeter Maydell return false; 3395654a5173SPeter Maydell } 3396654a5173SPeter Maydell 3397654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3398654a5173SPeter Maydell return false; 3399654a5173SPeter Maydell } 3400654a5173SPeter Maydell 3401654a5173SPeter Maydell if (!vfp_access_check(s)) { 3402654a5173SPeter Maydell return true; 3403654a5173SPeter Maydell } 3404654a5173SPeter Maydell 3405a84d1d13SPeter Maydell fpst = fpstatus_ptr(FPST_STD); 3406654a5173SPeter Maydell ahp = get_ahp_flag(); 3407654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3408a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3409a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3410a712266fSRichard Henderson read_neon_element32(tmp, a->vm, 0, MO_32); 3411a712266fSRichard Henderson read_neon_element32(tmp2, a->vm, 1, MO_32); 3412654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3413654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3414a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 0, MO_32); 3415654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3416654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3417a712266fSRichard Henderson write_neon_element32(tmp, a->vd, 1, MO_32); 3418a712266fSRichard Henderson tcg_temp_free_i32(tmp); 3419654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3420654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3421a712266fSRichard Henderson write_neon_element32(tmp3, a->vd, 2, MO_32); 3422a712266fSRichard Henderson tcg_temp_free_i32(tmp3); 3423654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3424654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3425a712266fSRichard Henderson write_neon_element32(tmp2, a->vd, 3, MO_32); 3426a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3427654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3428654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3429654a5173SPeter Maydell 3430654a5173SPeter Maydell return true; 3431654a5173SPeter Maydell } 343275153179SPeter Maydell 343375153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 343475153179SPeter Maydell { 343575153179SPeter Maydell int vec_size = a->q ? 16 : 8; 3436015ee81aSRichard Henderson int rd_ofs = neon_full_reg_offset(a->vd); 3437015ee81aSRichard Henderson int rm_ofs = neon_full_reg_offset(a->vm); 343875153179SPeter Maydell 343975153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 344075153179SPeter Maydell return false; 344175153179SPeter Maydell } 344275153179SPeter Maydell 344375153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 344475153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 344575153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 344675153179SPeter Maydell return false; 344775153179SPeter Maydell } 344875153179SPeter Maydell 344975153179SPeter Maydell if (a->size == 3) { 345075153179SPeter Maydell return false; 345175153179SPeter Maydell } 345275153179SPeter Maydell 345375153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 345475153179SPeter Maydell return false; 345575153179SPeter Maydell } 345675153179SPeter Maydell 345775153179SPeter Maydell if (!vfp_access_check(s)) { 345875153179SPeter Maydell return true; 345975153179SPeter Maydell } 346075153179SPeter Maydell 346175153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 346275153179SPeter Maydell 346375153179SPeter Maydell return true; 346475153179SPeter Maydell } 346575153179SPeter Maydell 346675153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 346775153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 346875153179SPeter Maydell { \ 346975153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 347075153179SPeter Maydell } 347175153179SPeter Maydell 347275153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 347375153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 347475153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 347575153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 347675153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 347775153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 347875153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 347975153179SPeter Maydell 348075153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 348175153179SPeter Maydell { 348275153179SPeter Maydell if (a->size != 0) { 348375153179SPeter Maydell return false; 348475153179SPeter Maydell } 348575153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 348675153179SPeter Maydell } 34870b30dd5bSPeter Maydell 34880b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 34890b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 34900b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 34910b30dd5bSPeter Maydell uint32_t maxsz) \ 34920b30dd5bSPeter Maydell { \ 34930b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 34940b30dd5bSPeter Maydell DATA, FUNC); \ 34950b30dd5bSPeter Maydell } 34960b30dd5bSPeter Maydell 34970b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 34980b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 34990b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35000b30dd5bSPeter Maydell uint32_t maxsz) \ 35010b30dd5bSPeter Maydell { \ 35020b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 35030b30dd5bSPeter Maydell } 35040b30dd5bSPeter Maydell 35050b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 35060b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 35070b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 35080b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 35090b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 35100b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 35110b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 35120b30dd5bSPeter Maydell 35130b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 35140b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 35150b30dd5bSPeter Maydell { \ 35160b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 35170b30dd5bSPeter Maydell return false; \ 35180b30dd5bSPeter Maydell } \ 35190b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 35200b30dd5bSPeter Maydell } 35210b30dd5bSPeter Maydell 35220b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 35230b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 35240b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 35250b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 35260b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 35270b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 35280b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 352989668082SPeter Maydell 353089668082SPeter Maydell static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) 353189668082SPeter Maydell { 3532a712266fSRichard Henderson TCGv_i32 tmp; 353389668082SPeter Maydell int pass; 353489668082SPeter Maydell 353589668082SPeter Maydell /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ 353689668082SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 353789668082SPeter Maydell return false; 353889668082SPeter Maydell } 353989668082SPeter Maydell 354089668082SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 354189668082SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 354289668082SPeter Maydell ((a->vd | a->vm) & 0x10)) { 354389668082SPeter Maydell return false; 354489668082SPeter Maydell } 354589668082SPeter Maydell 354689668082SPeter Maydell if (!fn) { 354789668082SPeter Maydell return false; 354889668082SPeter Maydell } 354989668082SPeter Maydell 355089668082SPeter Maydell if ((a->vd | a->vm) & a->q) { 355189668082SPeter Maydell return false; 355289668082SPeter Maydell } 355389668082SPeter Maydell 355489668082SPeter Maydell if (!vfp_access_check(s)) { 355589668082SPeter Maydell return true; 355689668082SPeter Maydell } 355789668082SPeter Maydell 3558a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 355989668082SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3560a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 356189668082SPeter Maydell fn(tmp, tmp); 3562a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 356389668082SPeter Maydell } 3564a712266fSRichard Henderson tcg_temp_free_i32(tmp); 356589668082SPeter Maydell 356689668082SPeter Maydell return true; 356789668082SPeter Maydell } 356889668082SPeter Maydell 356989668082SPeter Maydell static bool trans_VREV32(DisasContext *s, arg_2misc *a) 357089668082SPeter Maydell { 357189668082SPeter Maydell static NeonGenOneOpFn * const fn[] = { 357289668082SPeter Maydell tcg_gen_bswap32_i32, 357389668082SPeter Maydell gen_swap_half, 357489668082SPeter Maydell NULL, 357589668082SPeter Maydell NULL, 357689668082SPeter Maydell }; 357789668082SPeter Maydell return do_2misc(s, a, fn[a->size]); 357889668082SPeter Maydell } 357989668082SPeter Maydell 358089668082SPeter Maydell static bool trans_VREV16(DisasContext *s, arg_2misc *a) 358189668082SPeter Maydell { 358289668082SPeter Maydell if (a->size != 0) { 358389668082SPeter Maydell return false; 358489668082SPeter Maydell } 358589668082SPeter Maydell return do_2misc(s, a, gen_rev16); 358689668082SPeter Maydell } 358784eae770SPeter Maydell 358884eae770SPeter Maydell static bool trans_VCLS(DisasContext *s, arg_2misc *a) 358984eae770SPeter Maydell { 359084eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 359184eae770SPeter Maydell gen_helper_neon_cls_s8, 359284eae770SPeter Maydell gen_helper_neon_cls_s16, 359384eae770SPeter Maydell gen_helper_neon_cls_s32, 359484eae770SPeter Maydell NULL, 359584eae770SPeter Maydell }; 359684eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 359784eae770SPeter Maydell } 359884eae770SPeter Maydell 359984eae770SPeter Maydell static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) 360084eae770SPeter Maydell { 360184eae770SPeter Maydell tcg_gen_clzi_i32(rd, rm, 32); 360284eae770SPeter Maydell } 360384eae770SPeter Maydell 360484eae770SPeter Maydell static bool trans_VCLZ(DisasContext *s, arg_2misc *a) 360584eae770SPeter Maydell { 360684eae770SPeter Maydell static NeonGenOneOpFn * const fn[] = { 360784eae770SPeter Maydell gen_helper_neon_clz_u8, 360884eae770SPeter Maydell gen_helper_neon_clz_u16, 360984eae770SPeter Maydell do_VCLZ_32, 361084eae770SPeter Maydell NULL, 361184eae770SPeter Maydell }; 361284eae770SPeter Maydell return do_2misc(s, a, fn[a->size]); 361384eae770SPeter Maydell } 361484eae770SPeter Maydell 361584eae770SPeter Maydell static bool trans_VCNT(DisasContext *s, arg_2misc *a) 361684eae770SPeter Maydell { 361784eae770SPeter Maydell if (a->size != 0) { 361884eae770SPeter Maydell return false; 361984eae770SPeter Maydell } 362084eae770SPeter Maydell return do_2misc(s, a, gen_helper_neon_cnt_u8); 362184eae770SPeter Maydell } 362284eae770SPeter Maydell 36232b70d8cdSPeter Maydell static void gen_VABS_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 36242b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 36252b70d8cdSPeter Maydell { 36262b70d8cdSPeter Maydell tcg_gen_gvec_andi(vece, rd_ofs, rm_ofs, 36272b70d8cdSPeter Maydell vece == MO_16 ? 0x7fff : 0x7fffffff, 36282b70d8cdSPeter Maydell oprsz, maxsz); 36292b70d8cdSPeter Maydell } 36302b70d8cdSPeter Maydell 363184eae770SPeter Maydell static bool trans_VABS_F(DisasContext *s, arg_2misc *a) 363284eae770SPeter Maydell { 36332b70d8cdSPeter Maydell if (a->size == MO_16) { 36342b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 363584eae770SPeter Maydell return false; 363684eae770SPeter Maydell } 36372b70d8cdSPeter Maydell } else if (a->size != MO_32) { 36382b70d8cdSPeter Maydell return false; 36392b70d8cdSPeter Maydell } 36402b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VABS_F); 36412b70d8cdSPeter Maydell } 36422b70d8cdSPeter Maydell 36432b70d8cdSPeter Maydell static void gen_VNEG_F(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 36442b70d8cdSPeter Maydell uint32_t oprsz, uint32_t maxsz) 36452b70d8cdSPeter Maydell { 36462b70d8cdSPeter Maydell tcg_gen_gvec_xori(vece, rd_ofs, rm_ofs, 36472b70d8cdSPeter Maydell vece == MO_16 ? 0x8000 : 0x80000000, 36482b70d8cdSPeter Maydell oprsz, maxsz); 364984eae770SPeter Maydell } 365084eae770SPeter Maydell 365184eae770SPeter Maydell static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) 365284eae770SPeter Maydell { 36532b70d8cdSPeter Maydell if (a->size == MO_16) { 36542b70d8cdSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { 365584eae770SPeter Maydell return false; 365684eae770SPeter Maydell } 36572b70d8cdSPeter Maydell } else if (a->size != MO_32) { 36582b70d8cdSPeter Maydell return false; 36592b70d8cdSPeter Maydell } 36602b70d8cdSPeter Maydell return do_2misc_vec(s, a, gen_VNEG_F); 366184eae770SPeter Maydell } 366284eae770SPeter Maydell 366384eae770SPeter Maydell static bool trans_VRECPE(DisasContext *s, arg_2misc *a) 366484eae770SPeter Maydell { 366584eae770SPeter Maydell if (a->size != 2) { 366684eae770SPeter Maydell return false; 366784eae770SPeter Maydell } 366884eae770SPeter Maydell return do_2misc(s, a, gen_helper_recpe_u32); 366984eae770SPeter Maydell } 367084eae770SPeter Maydell 367184eae770SPeter Maydell static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) 367284eae770SPeter Maydell { 367384eae770SPeter Maydell if (a->size != 2) { 367484eae770SPeter Maydell return false; 367584eae770SPeter Maydell } 367684eae770SPeter Maydell return do_2misc(s, a, gen_helper_rsqrte_u32); 367784eae770SPeter Maydell } 36784936f38aSPeter Maydell 36794936f38aSPeter Maydell #define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ 36804936f38aSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ 36814936f38aSPeter Maydell { \ 36824936f38aSPeter Maydell FUNC(d, cpu_env, m); \ 36834936f38aSPeter Maydell } 36844936f38aSPeter Maydell 36854936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) 36864936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) 36874936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) 36884936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) 36894936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) 36904936f38aSPeter Maydell WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) 36914936f38aSPeter Maydell 36924936f38aSPeter Maydell static bool trans_VQABS(DisasContext *s, arg_2misc *a) 36934936f38aSPeter Maydell { 36944936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 36954936f38aSPeter Maydell gen_VQABS_s8, 36964936f38aSPeter Maydell gen_VQABS_s16, 36974936f38aSPeter Maydell gen_VQABS_s32, 36984936f38aSPeter Maydell NULL, 36994936f38aSPeter Maydell }; 37004936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 37014936f38aSPeter Maydell } 37024936f38aSPeter Maydell 37034936f38aSPeter Maydell static bool trans_VQNEG(DisasContext *s, arg_2misc *a) 37044936f38aSPeter Maydell { 37054936f38aSPeter Maydell static NeonGenOneOpFn * const fn[] = { 37064936f38aSPeter Maydell gen_VQNEG_s8, 37074936f38aSPeter Maydell gen_VQNEG_s16, 37084936f38aSPeter Maydell gen_VQNEG_s32, 37094936f38aSPeter Maydell NULL, 37104936f38aSPeter Maydell }; 37114936f38aSPeter Maydell return do_2misc(s, a, fn[a->size]); 37124936f38aSPeter Maydell } 37133e96b205SPeter Maydell 37144a15d9a3SPeter Maydell #define DO_2MISC_FP_VEC(INSN, HFUNC, SFUNC) \ 37154a15d9a3SPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 37164a15d9a3SPeter Maydell uint32_t rm_ofs, \ 37174a15d9a3SPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 37184a15d9a3SPeter Maydell { \ 37194a15d9a3SPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 37204a15d9a3SPeter Maydell NULL, HFUNC, SFUNC, NULL, \ 37214a15d9a3SPeter Maydell }; \ 37224a15d9a3SPeter Maydell TCGv_ptr fpst; \ 37234a15d9a3SPeter Maydell fpst = fpstatus_ptr(vece == MO_16 ? FPST_STD_F16 : FPST_STD); \ 37244a15d9a3SPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, 0, \ 37254a15d9a3SPeter Maydell fns[vece]); \ 37264a15d9a3SPeter Maydell tcg_temp_free_ptr(fpst); \ 37274a15d9a3SPeter Maydell } \ 37284a15d9a3SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 37294a15d9a3SPeter Maydell { \ 37304a15d9a3SPeter Maydell if (a->size == MO_16) { \ 37314a15d9a3SPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 37324a15d9a3SPeter Maydell return false; \ 37334a15d9a3SPeter Maydell } \ 37344a15d9a3SPeter Maydell } else if (a->size != MO_32) { \ 37354a15d9a3SPeter Maydell return false; \ 37364a15d9a3SPeter Maydell } \ 37374a15d9a3SPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 37384a15d9a3SPeter Maydell } 37394a15d9a3SPeter Maydell 37404a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRECPE_F, gen_helper_gvec_frecpe_h, gen_helper_gvec_frecpe_s) 37414a15d9a3SPeter Maydell DO_2MISC_FP_VEC(VRSQRTE_F, gen_helper_gvec_frsqrte_h, gen_helper_gvec_frsqrte_s) 3742635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGT0_F, gen_helper_gvec_fcgt0_h, gen_helper_gvec_fcgt0_s) 3743635187aaSPeter Maydell DO_2MISC_FP_VEC(VCGE0_F, gen_helper_gvec_fcge0_h, gen_helper_gvec_fcge0_s) 3744635187aaSPeter Maydell DO_2MISC_FP_VEC(VCEQ0_F, gen_helper_gvec_fceq0_h, gen_helper_gvec_fceq0_s) 3745635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLT0_F, gen_helper_gvec_fclt0_h, gen_helper_gvec_fclt0_s) 3746635187aaSPeter Maydell DO_2MISC_FP_VEC(VCLE0_F, gen_helper_gvec_fcle0_h, gen_helper_gvec_fcle0_s) 37477782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FS, gen_helper_gvec_sstoh, gen_helper_gvec_sitos) 37487782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_FU, gen_helper_gvec_ustoh, gen_helper_gvec_uitos) 37497782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_SF, gen_helper_gvec_tosszh, gen_helper_gvec_tosizs) 37507782a9afSPeter Maydell DO_2MISC_FP_VEC(VCVT_UF, gen_helper_gvec_touszh, gen_helper_gvec_touizs) 37514a15d9a3SPeter Maydell 375223afcdd2SPeter Maydell DO_2MISC_FP_VEC(VRINTX_impl, gen_helper_gvec_vrintx_h, gen_helper_gvec_vrintx_s) 375323afcdd2SPeter Maydell 37543e96b205SPeter Maydell static bool trans_VRINTX(DisasContext *s, arg_2misc *a) 37553e96b205SPeter Maydell { 37563e96b205SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 37573e96b205SPeter Maydell return false; 37583e96b205SPeter Maydell } 375923afcdd2SPeter Maydell return trans_VRINTX_impl(s, a); 37603e96b205SPeter Maydell } 3761baa59323SPeter Maydell 3762ca88a6efSPeter Maydell #define DO_VEC_RMODE(INSN, RMODE, OP) \ 3763ca88a6efSPeter Maydell static void gen_##INSN(unsigned vece, uint32_t rd_ofs, \ 3764ca88a6efSPeter Maydell uint32_t rm_ofs, \ 3765ca88a6efSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 3766ca88a6efSPeter Maydell { \ 3767ca88a6efSPeter Maydell static gen_helper_gvec_2_ptr * const fns[4] = { \ 3768ca88a6efSPeter Maydell NULL, \ 3769ca88a6efSPeter Maydell gen_helper_gvec_##OP##h, \ 3770ca88a6efSPeter Maydell gen_helper_gvec_##OP##s, \ 3771ca88a6efSPeter Maydell NULL, \ 3772ca88a6efSPeter Maydell }; \ 3773ca88a6efSPeter Maydell TCGv_ptr fpst; \ 3774ca88a6efSPeter Maydell fpst = fpstatus_ptr(vece == 1 ? FPST_STD_F16 : FPST_STD); \ 3775ca88a6efSPeter Maydell tcg_gen_gvec_2_ptr(rd_ofs, rm_ofs, fpst, oprsz, maxsz, \ 3776ca88a6efSPeter Maydell arm_rmode_to_sf(RMODE), fns[vece]); \ 3777ca88a6efSPeter Maydell tcg_temp_free_ptr(fpst); \ 3778ca88a6efSPeter Maydell } \ 3779a183d5fbSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 3780a183d5fbSPeter Maydell { \ 3781ca88a6efSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { \ 3782ca88a6efSPeter Maydell return false; \ 3783ca88a6efSPeter Maydell } \ 3784ca88a6efSPeter Maydell if (a->size == MO_16) { \ 3785ca88a6efSPeter Maydell if (!dc_isar_feature(aa32_fp16_arith, s)) { \ 3786ca88a6efSPeter Maydell return false; \ 3787ca88a6efSPeter Maydell } \ 3788ca88a6efSPeter Maydell } else if (a->size != MO_32) { \ 3789ca88a6efSPeter Maydell return false; \ 3790ca88a6efSPeter Maydell } \ 3791ca88a6efSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 3792a183d5fbSPeter Maydell } 3793a183d5fbSPeter Maydell 3794ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAU, FPROUNDING_TIEAWAY, vcvt_rm_u) 3795ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTAS, FPROUNDING_TIEAWAY, vcvt_rm_s) 3796ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNU, FPROUNDING_TIEEVEN, vcvt_rm_u) 3797ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTNS, FPROUNDING_TIEEVEN, vcvt_rm_s) 3798ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPU, FPROUNDING_POSINF, vcvt_rm_u) 3799ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTPS, FPROUNDING_POSINF, vcvt_rm_s) 3800ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMU, FPROUNDING_NEGINF, vcvt_rm_u) 3801ca88a6efSPeter Maydell DO_VEC_RMODE(VCVTMS, FPROUNDING_NEGINF, vcvt_rm_s) 38028ab3a227SPeter Maydell 380318725916SPeter Maydell DO_VEC_RMODE(VRINTN, FPROUNDING_TIEEVEN, vrint_rm_) 380418725916SPeter Maydell DO_VEC_RMODE(VRINTA, FPROUNDING_TIEAWAY, vrint_rm_) 380518725916SPeter Maydell DO_VEC_RMODE(VRINTZ, FPROUNDING_ZERO, vrint_rm_) 380618725916SPeter Maydell DO_VEC_RMODE(VRINTM, FPROUNDING_NEGINF, vrint_rm_) 380718725916SPeter Maydell DO_VEC_RMODE(VRINTP, FPROUNDING_POSINF, vrint_rm_) 380818725916SPeter Maydell 38098ab3a227SPeter Maydell static bool trans_VSWP(DisasContext *s, arg_2misc *a) 38108ab3a227SPeter Maydell { 38118ab3a227SPeter Maydell TCGv_i64 rm, rd; 38128ab3a227SPeter Maydell int pass; 38138ab3a227SPeter Maydell 38148ab3a227SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 38158ab3a227SPeter Maydell return false; 38168ab3a227SPeter Maydell } 38178ab3a227SPeter Maydell 38188ab3a227SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 38198ab3a227SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 38208ab3a227SPeter Maydell ((a->vd | a->vm) & 0x10)) { 38218ab3a227SPeter Maydell return false; 38228ab3a227SPeter Maydell } 38238ab3a227SPeter Maydell 38248ab3a227SPeter Maydell if (a->size != 0) { 38258ab3a227SPeter Maydell return false; 38268ab3a227SPeter Maydell } 38278ab3a227SPeter Maydell 38288ab3a227SPeter Maydell if ((a->vd | a->vm) & a->q) { 38298ab3a227SPeter Maydell return false; 38308ab3a227SPeter Maydell } 38318ab3a227SPeter Maydell 38328ab3a227SPeter Maydell if (!vfp_access_check(s)) { 38338ab3a227SPeter Maydell return true; 38348ab3a227SPeter Maydell } 38358ab3a227SPeter Maydell 38368ab3a227SPeter Maydell rm = tcg_temp_new_i64(); 38378ab3a227SPeter Maydell rd = tcg_temp_new_i64(); 38388ab3a227SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 38390aa8e700SRichard Henderson read_neon_element64(rm, a->vm, pass, MO_64); 38400aa8e700SRichard Henderson read_neon_element64(rd, a->vd, pass, MO_64); 38410aa8e700SRichard Henderson write_neon_element64(rm, a->vd, pass, MO_64); 38420aa8e700SRichard Henderson write_neon_element64(rd, a->vm, pass, MO_64); 38438ab3a227SPeter Maydell } 38448ab3a227SPeter Maydell tcg_temp_free_i64(rm); 38458ab3a227SPeter Maydell tcg_temp_free_i64(rd); 38468ab3a227SPeter Maydell 38478ab3a227SPeter Maydell return true; 38488ab3a227SPeter Maydell } 3849d4366190SPeter Maydell static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) 3850d4366190SPeter Maydell { 3851d4366190SPeter Maydell TCGv_i32 rd, tmp; 3852d4366190SPeter Maydell 3853d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3854d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3855d4366190SPeter Maydell 3856d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 8); 3857d4366190SPeter Maydell tcg_gen_andi_i32(rd, rd, 0xff00ff00); 3858d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); 3859d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3860d4366190SPeter Maydell 3861d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 8); 3862d4366190SPeter Maydell tcg_gen_andi_i32(t1, t1, 0x00ff00ff); 3863d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xff00ff00); 3864d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3865d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3866d4366190SPeter Maydell 3867d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3868d4366190SPeter Maydell tcg_temp_free_i32(rd); 3869d4366190SPeter Maydell } 3870d4366190SPeter Maydell 3871d4366190SPeter Maydell static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) 3872d4366190SPeter Maydell { 3873d4366190SPeter Maydell TCGv_i32 rd, tmp; 3874d4366190SPeter Maydell 3875d4366190SPeter Maydell rd = tcg_temp_new_i32(); 3876d4366190SPeter Maydell tmp = tcg_temp_new_i32(); 3877d4366190SPeter Maydell 3878d4366190SPeter Maydell tcg_gen_shli_i32(rd, t0, 16); 3879d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t1, 0xffff); 3880d4366190SPeter Maydell tcg_gen_or_i32(rd, rd, tmp); 3881d4366190SPeter Maydell tcg_gen_shri_i32(t1, t1, 16); 3882d4366190SPeter Maydell tcg_gen_andi_i32(tmp, t0, 0xffff0000); 3883d4366190SPeter Maydell tcg_gen_or_i32(t1, t1, tmp); 3884d4366190SPeter Maydell tcg_gen_mov_i32(t0, rd); 3885d4366190SPeter Maydell 3886d4366190SPeter Maydell tcg_temp_free_i32(tmp); 3887d4366190SPeter Maydell tcg_temp_free_i32(rd); 3888d4366190SPeter Maydell } 3889d4366190SPeter Maydell 3890d4366190SPeter Maydell static bool trans_VTRN(DisasContext *s, arg_2misc *a) 3891d4366190SPeter Maydell { 3892d4366190SPeter Maydell TCGv_i32 tmp, tmp2; 3893d4366190SPeter Maydell int pass; 3894d4366190SPeter Maydell 3895d4366190SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3896d4366190SPeter Maydell return false; 3897d4366190SPeter Maydell } 3898d4366190SPeter Maydell 3899d4366190SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3900d4366190SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3901d4366190SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3902d4366190SPeter Maydell return false; 3903d4366190SPeter Maydell } 3904d4366190SPeter Maydell 3905d4366190SPeter Maydell if ((a->vd | a->vm) & a->q) { 3906d4366190SPeter Maydell return false; 3907d4366190SPeter Maydell } 3908d4366190SPeter Maydell 3909d4366190SPeter Maydell if (a->size == 3) { 3910d4366190SPeter Maydell return false; 3911d4366190SPeter Maydell } 3912d4366190SPeter Maydell 3913d4366190SPeter Maydell if (!vfp_access_check(s)) { 3914d4366190SPeter Maydell return true; 3915d4366190SPeter Maydell } 3916d4366190SPeter Maydell 3917a712266fSRichard Henderson tmp = tcg_temp_new_i32(); 3918a712266fSRichard Henderson tmp2 = tcg_temp_new_i32(); 3919a712266fSRichard Henderson if (a->size == MO_32) { 3920d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { 3921a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3922a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass + 1, MO_32); 3923a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3924a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass + 1, MO_32); 3925d4366190SPeter Maydell } 3926d4366190SPeter Maydell } else { 3927d4366190SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 3928a712266fSRichard Henderson read_neon_element32(tmp, a->vm, pass, MO_32); 3929a712266fSRichard Henderson read_neon_element32(tmp2, a->vd, pass, MO_32); 3930a712266fSRichard Henderson if (a->size == MO_8) { 3931d4366190SPeter Maydell gen_neon_trn_u8(tmp, tmp2); 3932d4366190SPeter Maydell } else { 3933d4366190SPeter Maydell gen_neon_trn_u16(tmp, tmp2); 3934d4366190SPeter Maydell } 3935a712266fSRichard Henderson write_neon_element32(tmp2, a->vm, pass, MO_32); 3936a712266fSRichard Henderson write_neon_element32(tmp, a->vd, pass, MO_32); 3937d4366190SPeter Maydell } 3938d4366190SPeter Maydell } 3939a712266fSRichard Henderson tcg_temp_free_i32(tmp); 3940a712266fSRichard Henderson tcg_temp_free_i32(tmp2); 3941d4366190SPeter Maydell return true; 3942d4366190SPeter Maydell } 3943