1625e3dd4SPeter Maydell /* 2625e3dd4SPeter Maydell * ARM translation: AArch32 Neon instructions 3625e3dd4SPeter Maydell * 4625e3dd4SPeter Maydell * Copyright (c) 2003 Fabrice Bellard 5625e3dd4SPeter Maydell * Copyright (c) 2005-2007 CodeSourcery 6625e3dd4SPeter Maydell * Copyright (c) 2007 OpenedHand, Ltd. 7625e3dd4SPeter Maydell * Copyright (c) 2020 Linaro, Ltd. 8625e3dd4SPeter Maydell * 9625e3dd4SPeter Maydell * This library is free software; you can redistribute it and/or 10625e3dd4SPeter Maydell * modify it under the terms of the GNU Lesser General Public 11625e3dd4SPeter Maydell * License as published by the Free Software Foundation; either 12625e3dd4SPeter Maydell * version 2 of the License, or (at your option) any later version. 13625e3dd4SPeter Maydell * 14625e3dd4SPeter Maydell * This library is distributed in the hope that it will be useful, 15625e3dd4SPeter Maydell * but WITHOUT ANY WARRANTY; without even the implied warranty of 16625e3dd4SPeter Maydell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17625e3dd4SPeter Maydell * Lesser General Public License for more details. 18625e3dd4SPeter Maydell * 19625e3dd4SPeter Maydell * You should have received a copy of the GNU Lesser General Public 20625e3dd4SPeter Maydell * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21625e3dd4SPeter Maydell */ 22625e3dd4SPeter Maydell 23625e3dd4SPeter Maydell /* 24625e3dd4SPeter Maydell * This file is intended to be included from translate.c; it uses 25625e3dd4SPeter Maydell * some macros and definitions provided by that file. 26625e3dd4SPeter Maydell * It might be possible to convert it to a standalone .c file eventually. 27625e3dd4SPeter Maydell */ 28625e3dd4SPeter Maydell 29123ce4e3SPeter Maydell static inline int plus1(DisasContext *s, int x) 30123ce4e3SPeter Maydell { 31123ce4e3SPeter Maydell return x + 1; 32123ce4e3SPeter Maydell } 33123ce4e3SPeter Maydell 3466432d6bSPeter Maydell static inline int rsub_64(DisasContext *s, int x) 3566432d6bSPeter Maydell { 3666432d6bSPeter Maydell return 64 - x; 3766432d6bSPeter Maydell } 3866432d6bSPeter Maydell 3966432d6bSPeter Maydell static inline int rsub_32(DisasContext *s, int x) 4066432d6bSPeter Maydell { 4166432d6bSPeter Maydell return 32 - x; 4266432d6bSPeter Maydell } 4366432d6bSPeter Maydell static inline int rsub_16(DisasContext *s, int x) 4466432d6bSPeter Maydell { 4566432d6bSPeter Maydell return 16 - x; 4666432d6bSPeter Maydell } 4766432d6bSPeter Maydell static inline int rsub_8(DisasContext *s, int x) 4866432d6bSPeter Maydell { 4966432d6bSPeter Maydell return 8 - x; 5066432d6bSPeter Maydell } 5166432d6bSPeter Maydell 52625e3dd4SPeter Maydell /* Include the generated Neon decoder */ 53625e3dd4SPeter Maydell #include "decode-neon-dp.inc.c" 54625e3dd4SPeter Maydell #include "decode-neon-ls.inc.c" 55625e3dd4SPeter Maydell #include "decode-neon-shared.inc.c" 56afff8de0SPeter Maydell 57afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) 58afff8de0SPeter Maydell { 59afff8de0SPeter Maydell int opr_sz; 60afff8de0SPeter Maydell TCGv_ptr fpst; 61afff8de0SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 62afff8de0SPeter Maydell 63afff8de0SPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 64afff8de0SPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 65afff8de0SPeter Maydell return false; 66afff8de0SPeter Maydell } 67afff8de0SPeter Maydell 68afff8de0SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 69afff8de0SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 70afff8de0SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 71afff8de0SPeter Maydell return false; 72afff8de0SPeter Maydell } 73afff8de0SPeter Maydell 74afff8de0SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 75afff8de0SPeter Maydell return false; 76afff8de0SPeter Maydell } 77afff8de0SPeter Maydell 78afff8de0SPeter Maydell if (!vfp_access_check(s)) { 79afff8de0SPeter Maydell return true; 80afff8de0SPeter Maydell } 81afff8de0SPeter Maydell 82afff8de0SPeter Maydell opr_sz = (1 + a->q) * 8; 83afff8de0SPeter Maydell fpst = get_fpstatus_ptr(1); 84afff8de0SPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah; 85afff8de0SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 86afff8de0SPeter Maydell vfp_reg_offset(1, a->vn), 87afff8de0SPeter Maydell vfp_reg_offset(1, a->vm), 88afff8de0SPeter Maydell fpst, opr_sz, opr_sz, a->rot, 89afff8de0SPeter Maydell fn_gvec_ptr); 90afff8de0SPeter Maydell tcg_temp_free_ptr(fpst); 91afff8de0SPeter Maydell return true; 92afff8de0SPeter Maydell } 9394d5eb7bSPeter Maydell 9494d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a) 9594d5eb7bSPeter Maydell { 9694d5eb7bSPeter Maydell int opr_sz; 9794d5eb7bSPeter Maydell TCGv_ptr fpst; 9894d5eb7bSPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 9994d5eb7bSPeter Maydell 10094d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_vcma, s) 10194d5eb7bSPeter Maydell || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) { 10294d5eb7bSPeter Maydell return false; 10394d5eb7bSPeter Maydell } 10494d5eb7bSPeter Maydell 10594d5eb7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 10694d5eb7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 10794d5eb7bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 10894d5eb7bSPeter Maydell return false; 10994d5eb7bSPeter Maydell } 11094d5eb7bSPeter Maydell 11194d5eb7bSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 11294d5eb7bSPeter Maydell return false; 11394d5eb7bSPeter Maydell } 11494d5eb7bSPeter Maydell 11594d5eb7bSPeter Maydell if (!vfp_access_check(s)) { 11694d5eb7bSPeter Maydell return true; 11794d5eb7bSPeter Maydell } 11894d5eb7bSPeter Maydell 11994d5eb7bSPeter Maydell opr_sz = (1 + a->q) * 8; 12094d5eb7bSPeter Maydell fpst = get_fpstatus_ptr(1); 12194d5eb7bSPeter Maydell fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh; 12294d5eb7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 12394d5eb7bSPeter Maydell vfp_reg_offset(1, a->vn), 12494d5eb7bSPeter Maydell vfp_reg_offset(1, a->vm), 12594d5eb7bSPeter Maydell fpst, opr_sz, opr_sz, a->rot, 12694d5eb7bSPeter Maydell fn_gvec_ptr); 12794d5eb7bSPeter Maydell tcg_temp_free_ptr(fpst); 12894d5eb7bSPeter Maydell return true; 12994d5eb7bSPeter Maydell } 13032da0e33SPeter Maydell 13132da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a) 13232da0e33SPeter Maydell { 13332da0e33SPeter Maydell int opr_sz; 13432da0e33SPeter Maydell gen_helper_gvec_3 *fn_gvec; 13532da0e33SPeter Maydell 13632da0e33SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 13732da0e33SPeter Maydell return false; 13832da0e33SPeter Maydell } 13932da0e33SPeter Maydell 14032da0e33SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 14132da0e33SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 14232da0e33SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 14332da0e33SPeter Maydell return false; 14432da0e33SPeter Maydell } 14532da0e33SPeter Maydell 14632da0e33SPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 14732da0e33SPeter Maydell return false; 14832da0e33SPeter Maydell } 14932da0e33SPeter Maydell 15032da0e33SPeter Maydell if (!vfp_access_check(s)) { 15132da0e33SPeter Maydell return true; 15232da0e33SPeter Maydell } 15332da0e33SPeter Maydell 15432da0e33SPeter Maydell opr_sz = (1 + a->q) * 8; 15532da0e33SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; 15632da0e33SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 15732da0e33SPeter Maydell vfp_reg_offset(1, a->vn), 15832da0e33SPeter Maydell vfp_reg_offset(1, a->vm), 15932da0e33SPeter Maydell opr_sz, opr_sz, 0, fn_gvec); 16032da0e33SPeter Maydell return true; 16132da0e33SPeter Maydell } 1629a107e7bSPeter Maydell 1639a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a) 1649a107e7bSPeter Maydell { 1659a107e7bSPeter Maydell int opr_sz; 1669a107e7bSPeter Maydell 1679a107e7bSPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 1689a107e7bSPeter Maydell return false; 1699a107e7bSPeter Maydell } 1709a107e7bSPeter Maydell 1719a107e7bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1729a107e7bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1739a107e7bSPeter Maydell (a->vd & 0x10)) { 1749a107e7bSPeter Maydell return false; 1759a107e7bSPeter Maydell } 1769a107e7bSPeter Maydell 1779a107e7bSPeter Maydell if (a->vd & a->q) { 1789a107e7bSPeter Maydell return false; 1799a107e7bSPeter Maydell } 1809a107e7bSPeter Maydell 1819a107e7bSPeter Maydell if (!vfp_access_check(s)) { 1829a107e7bSPeter Maydell return true; 1839a107e7bSPeter Maydell } 1849a107e7bSPeter Maydell 1859a107e7bSPeter Maydell opr_sz = (1 + a->q) * 8; 1869a107e7bSPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 1879a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vn), 1889a107e7bSPeter Maydell vfp_reg_offset(a->q, a->vm), 1899a107e7bSPeter Maydell cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */ 1909a107e7bSPeter Maydell gen_helper_gvec_fmlal_a32); 1919a107e7bSPeter Maydell return true; 1929a107e7bSPeter Maydell } 1937e1b5d61SPeter Maydell 1947e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a) 1957e1b5d61SPeter Maydell { 1967e1b5d61SPeter Maydell gen_helper_gvec_3_ptr *fn_gvec_ptr; 1977e1b5d61SPeter Maydell int opr_sz; 1987e1b5d61SPeter Maydell TCGv_ptr fpst; 1997e1b5d61SPeter Maydell 2007e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_vcma, s)) { 2017e1b5d61SPeter Maydell return false; 2027e1b5d61SPeter Maydell } 2037e1b5d61SPeter Maydell if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) { 2047e1b5d61SPeter Maydell return false; 2057e1b5d61SPeter Maydell } 2067e1b5d61SPeter Maydell 2077e1b5d61SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2087e1b5d61SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2097e1b5d61SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2107e1b5d61SPeter Maydell return false; 2117e1b5d61SPeter Maydell } 2127e1b5d61SPeter Maydell 2137e1b5d61SPeter Maydell if ((a->vd | a->vn) & a->q) { 2147e1b5d61SPeter Maydell return false; 2157e1b5d61SPeter Maydell } 2167e1b5d61SPeter Maydell 2177e1b5d61SPeter Maydell if (!vfp_access_check(s)) { 2187e1b5d61SPeter Maydell return true; 2197e1b5d61SPeter Maydell } 2207e1b5d61SPeter Maydell 2217e1b5d61SPeter Maydell fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx 2227e1b5d61SPeter Maydell : gen_helper_gvec_fcmlah_idx); 2237e1b5d61SPeter Maydell opr_sz = (1 + a->q) * 8; 2247e1b5d61SPeter Maydell fpst = get_fpstatus_ptr(1); 2257e1b5d61SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 2267e1b5d61SPeter Maydell vfp_reg_offset(1, a->vn), 2277e1b5d61SPeter Maydell vfp_reg_offset(1, a->vm), 2287e1b5d61SPeter Maydell fpst, opr_sz, opr_sz, 2297e1b5d61SPeter Maydell (a->index << 2) | a->rot, fn_gvec_ptr); 2307e1b5d61SPeter Maydell tcg_temp_free_ptr(fpst); 2317e1b5d61SPeter Maydell return true; 2327e1b5d61SPeter Maydell } 23335f5d4d1SPeter Maydell 23435f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a) 23535f5d4d1SPeter Maydell { 23635f5d4d1SPeter Maydell gen_helper_gvec_3 *fn_gvec; 23735f5d4d1SPeter Maydell int opr_sz; 23835f5d4d1SPeter Maydell TCGv_ptr fpst; 23935f5d4d1SPeter Maydell 24035f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_dp, s)) { 24135f5d4d1SPeter Maydell return false; 24235f5d4d1SPeter Maydell } 24335f5d4d1SPeter Maydell 24435f5d4d1SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 24535f5d4d1SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 24635f5d4d1SPeter Maydell ((a->vd | a->vn) & 0x10)) { 24735f5d4d1SPeter Maydell return false; 24835f5d4d1SPeter Maydell } 24935f5d4d1SPeter Maydell 25035f5d4d1SPeter Maydell if ((a->vd | a->vn) & a->q) { 25135f5d4d1SPeter Maydell return false; 25235f5d4d1SPeter Maydell } 25335f5d4d1SPeter Maydell 25435f5d4d1SPeter Maydell if (!vfp_access_check(s)) { 25535f5d4d1SPeter Maydell return true; 25635f5d4d1SPeter Maydell } 25735f5d4d1SPeter Maydell 25835f5d4d1SPeter Maydell fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b; 25935f5d4d1SPeter Maydell opr_sz = (1 + a->q) * 8; 26035f5d4d1SPeter Maydell fpst = get_fpstatus_ptr(1); 26135f5d4d1SPeter Maydell tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd), 26235f5d4d1SPeter Maydell vfp_reg_offset(1, a->vn), 26335f5d4d1SPeter Maydell vfp_reg_offset(1, a->rm), 26435f5d4d1SPeter Maydell opr_sz, opr_sz, a->index, fn_gvec); 26535f5d4d1SPeter Maydell tcg_temp_free_ptr(fpst); 26635f5d4d1SPeter Maydell return true; 26735f5d4d1SPeter Maydell } 268d27e82f7SPeter Maydell 269d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) 270d27e82f7SPeter Maydell { 271d27e82f7SPeter Maydell int opr_sz; 272d27e82f7SPeter Maydell 273d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_fhm, s)) { 274d27e82f7SPeter Maydell return false; 275d27e82f7SPeter Maydell } 276d27e82f7SPeter Maydell 277d27e82f7SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 278d27e82f7SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 279d27e82f7SPeter Maydell ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { 280d27e82f7SPeter Maydell return false; 281d27e82f7SPeter Maydell } 282d27e82f7SPeter Maydell 283d27e82f7SPeter Maydell if (a->vd & a->q) { 284d27e82f7SPeter Maydell return false; 285d27e82f7SPeter Maydell } 286d27e82f7SPeter Maydell 287d27e82f7SPeter Maydell if (!vfp_access_check(s)) { 288d27e82f7SPeter Maydell return true; 289d27e82f7SPeter Maydell } 290d27e82f7SPeter Maydell 291d27e82f7SPeter Maydell opr_sz = (1 + a->q) * 8; 292d27e82f7SPeter Maydell tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd), 293d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->vn), 294d27e82f7SPeter Maydell vfp_reg_offset(a->q, a->rm), 295d27e82f7SPeter Maydell cpu_env, opr_sz, opr_sz, 296d27e82f7SPeter Maydell (a->index << 2) | a->s, /* is_2 == 0 */ 297d27e82f7SPeter Maydell gen_helper_gvec_fmlal_idx_a32); 298d27e82f7SPeter Maydell return true; 299d27e82f7SPeter Maydell } 300a27b4630SPeter Maydell 301a27b4630SPeter Maydell static struct { 302a27b4630SPeter Maydell int nregs; 303a27b4630SPeter Maydell int interleave; 304a27b4630SPeter Maydell int spacing; 305a27b4630SPeter Maydell } const neon_ls_element_type[11] = { 306a27b4630SPeter Maydell {1, 4, 1}, 307a27b4630SPeter Maydell {1, 4, 2}, 308a27b4630SPeter Maydell {4, 1, 1}, 309a27b4630SPeter Maydell {2, 2, 2}, 310a27b4630SPeter Maydell {1, 3, 1}, 311a27b4630SPeter Maydell {1, 3, 2}, 312a27b4630SPeter Maydell {3, 1, 1}, 313a27b4630SPeter Maydell {1, 1, 1}, 314a27b4630SPeter Maydell {1, 2, 1}, 315a27b4630SPeter Maydell {1, 2, 2}, 316a27b4630SPeter Maydell {2, 1, 1} 317a27b4630SPeter Maydell }; 318a27b4630SPeter Maydell 319a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn, 320a27b4630SPeter Maydell int stride) 321a27b4630SPeter Maydell { 322a27b4630SPeter Maydell if (rm != 15) { 323a27b4630SPeter Maydell TCGv_i32 base; 324a27b4630SPeter Maydell 325a27b4630SPeter Maydell base = load_reg(s, rn); 326a27b4630SPeter Maydell if (rm == 13) { 327a27b4630SPeter Maydell tcg_gen_addi_i32(base, base, stride); 328a27b4630SPeter Maydell } else { 329a27b4630SPeter Maydell TCGv_i32 index; 330a27b4630SPeter Maydell index = load_reg(s, rm); 331a27b4630SPeter Maydell tcg_gen_add_i32(base, base, index); 332a27b4630SPeter Maydell tcg_temp_free_i32(index); 333a27b4630SPeter Maydell } 334a27b4630SPeter Maydell store_reg(s, rn, base); 335a27b4630SPeter Maydell } 336a27b4630SPeter Maydell } 337a27b4630SPeter Maydell 338a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) 339a27b4630SPeter Maydell { 340a27b4630SPeter Maydell /* Neon load/store multiple structures */ 341a27b4630SPeter Maydell int nregs, interleave, spacing, reg, n; 342a27b4630SPeter Maydell MemOp endian = s->be_data; 343a27b4630SPeter Maydell int mmu_idx = get_mem_index(s); 344a27b4630SPeter Maydell int size = a->size; 345a27b4630SPeter Maydell TCGv_i64 tmp64; 346a27b4630SPeter Maydell TCGv_i32 addr, tmp; 347a27b4630SPeter Maydell 348a27b4630SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 349a27b4630SPeter Maydell return false; 350a27b4630SPeter Maydell } 351a27b4630SPeter Maydell 352a27b4630SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 353a27b4630SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 354a27b4630SPeter Maydell return false; 355a27b4630SPeter Maydell } 356a27b4630SPeter Maydell if (a->itype > 10) { 357a27b4630SPeter Maydell return false; 358a27b4630SPeter Maydell } 359a27b4630SPeter Maydell /* Catch UNDEF cases for bad values of align field */ 360a27b4630SPeter Maydell switch (a->itype & 0xc) { 361a27b4630SPeter Maydell case 4: 362a27b4630SPeter Maydell if (a->align >= 2) { 363a27b4630SPeter Maydell return false; 364a27b4630SPeter Maydell } 365a27b4630SPeter Maydell break; 366a27b4630SPeter Maydell case 8: 367a27b4630SPeter Maydell if (a->align == 3) { 368a27b4630SPeter Maydell return false; 369a27b4630SPeter Maydell } 370a27b4630SPeter Maydell break; 371a27b4630SPeter Maydell default: 372a27b4630SPeter Maydell break; 373a27b4630SPeter Maydell } 374a27b4630SPeter Maydell nregs = neon_ls_element_type[a->itype].nregs; 375a27b4630SPeter Maydell interleave = neon_ls_element_type[a->itype].interleave; 376a27b4630SPeter Maydell spacing = neon_ls_element_type[a->itype].spacing; 377a27b4630SPeter Maydell if (size == 3 && (interleave | spacing) != 1) { 378a27b4630SPeter Maydell return false; 379a27b4630SPeter Maydell } 380a27b4630SPeter Maydell 381a27b4630SPeter Maydell if (!vfp_access_check(s)) { 382a27b4630SPeter Maydell return true; 383a27b4630SPeter Maydell } 384a27b4630SPeter Maydell 385a27b4630SPeter Maydell /* For our purposes, bytes are always little-endian. */ 386a27b4630SPeter Maydell if (size == 0) { 387a27b4630SPeter Maydell endian = MO_LE; 388a27b4630SPeter Maydell } 389a27b4630SPeter Maydell /* 390a27b4630SPeter Maydell * Consecutive little-endian elements from a single register 391a27b4630SPeter Maydell * can be promoted to a larger little-endian operation. 392a27b4630SPeter Maydell */ 393a27b4630SPeter Maydell if (interleave == 1 && endian == MO_LE) { 394a27b4630SPeter Maydell size = 3; 395a27b4630SPeter Maydell } 396a27b4630SPeter Maydell tmp64 = tcg_temp_new_i64(); 397a27b4630SPeter Maydell addr = tcg_temp_new_i32(); 398a27b4630SPeter Maydell tmp = tcg_const_i32(1 << size); 399a27b4630SPeter Maydell load_reg_var(s, addr, a->rn); 400a27b4630SPeter Maydell for (reg = 0; reg < nregs; reg++) { 401a27b4630SPeter Maydell for (n = 0; n < 8 >> size; n++) { 402a27b4630SPeter Maydell int xs; 403a27b4630SPeter Maydell for (xs = 0; xs < interleave; xs++) { 404a27b4630SPeter Maydell int tt = a->vd + reg + spacing * xs; 405a27b4630SPeter Maydell 406a27b4630SPeter Maydell if (a->l) { 407a27b4630SPeter Maydell gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); 408a27b4630SPeter Maydell neon_store_element64(tt, n, size, tmp64); 409a27b4630SPeter Maydell } else { 410a27b4630SPeter Maydell neon_load_element64(tmp64, tt, n, size); 411a27b4630SPeter Maydell gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); 412a27b4630SPeter Maydell } 413a27b4630SPeter Maydell tcg_gen_add_i32(addr, addr, tmp); 414a27b4630SPeter Maydell } 415a27b4630SPeter Maydell } 416a27b4630SPeter Maydell } 417a27b4630SPeter Maydell tcg_temp_free_i32(addr); 418a27b4630SPeter Maydell tcg_temp_free_i32(tmp); 419a27b4630SPeter Maydell tcg_temp_free_i64(tmp64); 420a27b4630SPeter Maydell 421a27b4630SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8); 422a27b4630SPeter Maydell return true; 423a27b4630SPeter Maydell } 4243698747cSPeter Maydell 4253698747cSPeter Maydell static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) 4263698747cSPeter Maydell { 4273698747cSPeter Maydell /* Neon load single structure to all lanes */ 4283698747cSPeter Maydell int reg, stride, vec_size; 4293698747cSPeter Maydell int vd = a->vd; 4303698747cSPeter Maydell int size = a->size; 4313698747cSPeter Maydell int nregs = a->n + 1; 4323698747cSPeter Maydell TCGv_i32 addr, tmp; 4333698747cSPeter Maydell 4343698747cSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 4353698747cSPeter Maydell return false; 4363698747cSPeter Maydell } 4373698747cSPeter Maydell 4383698747cSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 4393698747cSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 4403698747cSPeter Maydell return false; 4413698747cSPeter Maydell } 4423698747cSPeter Maydell 4433698747cSPeter Maydell if (size == 3) { 4443698747cSPeter Maydell if (nregs != 4 || a->a == 0) { 4453698747cSPeter Maydell return false; 4463698747cSPeter Maydell } 4473698747cSPeter Maydell /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ 4483698747cSPeter Maydell size = 2; 4493698747cSPeter Maydell } 4503698747cSPeter Maydell if (nregs == 1 && a->a == 1 && size == 0) { 4513698747cSPeter Maydell return false; 4523698747cSPeter Maydell } 4533698747cSPeter Maydell if (nregs == 3 && a->a == 1) { 4543698747cSPeter Maydell return false; 4553698747cSPeter Maydell } 4563698747cSPeter Maydell 4573698747cSPeter Maydell if (!vfp_access_check(s)) { 4583698747cSPeter Maydell return true; 4593698747cSPeter Maydell } 4603698747cSPeter Maydell 4613698747cSPeter Maydell /* 4623698747cSPeter Maydell * VLD1 to all lanes: T bit indicates how many Dregs to write. 4633698747cSPeter Maydell * VLD2/3/4 to all lanes: T bit indicates register stride. 4643698747cSPeter Maydell */ 4653698747cSPeter Maydell stride = a->t ? 2 : 1; 4663698747cSPeter Maydell vec_size = nregs == 1 ? stride * 8 : 8; 4673698747cSPeter Maydell 4683698747cSPeter Maydell tmp = tcg_temp_new_i32(); 4693698747cSPeter Maydell addr = tcg_temp_new_i32(); 4703698747cSPeter Maydell load_reg_var(s, addr, a->rn); 4713698747cSPeter Maydell for (reg = 0; reg < nregs; reg++) { 4723698747cSPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 4733698747cSPeter Maydell s->be_data | size); 4743698747cSPeter Maydell if ((vd & 1) && vec_size == 16) { 4753698747cSPeter Maydell /* 4763698747cSPeter Maydell * We cannot write 16 bytes at once because the 4773698747cSPeter Maydell * destination is unaligned. 4783698747cSPeter Maydell */ 4793698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 4803698747cSPeter Maydell 8, 8, tmp); 4813698747cSPeter Maydell tcg_gen_gvec_mov(0, neon_reg_offset(vd + 1, 0), 4823698747cSPeter Maydell neon_reg_offset(vd, 0), 8, 8); 4833698747cSPeter Maydell } else { 4843698747cSPeter Maydell tcg_gen_gvec_dup_i32(size, neon_reg_offset(vd, 0), 4853698747cSPeter Maydell vec_size, vec_size, tmp); 4863698747cSPeter Maydell } 4873698747cSPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << size); 4883698747cSPeter Maydell vd += stride; 4893698747cSPeter Maydell } 4903698747cSPeter Maydell tcg_temp_free_i32(tmp); 4913698747cSPeter Maydell tcg_temp_free_i32(addr); 4923698747cSPeter Maydell 4933698747cSPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << size) * nregs); 4943698747cSPeter Maydell 4953698747cSPeter Maydell return true; 4963698747cSPeter Maydell } 497123ce4e3SPeter Maydell 498123ce4e3SPeter Maydell static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) 499123ce4e3SPeter Maydell { 500123ce4e3SPeter Maydell /* Neon load/store single structure to one lane */ 501123ce4e3SPeter Maydell int reg; 502123ce4e3SPeter Maydell int nregs = a->n + 1; 503123ce4e3SPeter Maydell int vd = a->vd; 504123ce4e3SPeter Maydell TCGv_i32 addr, tmp; 505123ce4e3SPeter Maydell 506123ce4e3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 507123ce4e3SPeter Maydell return false; 508123ce4e3SPeter Maydell } 509123ce4e3SPeter Maydell 510123ce4e3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist */ 511123ce4e3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 512123ce4e3SPeter Maydell return false; 513123ce4e3SPeter Maydell } 514123ce4e3SPeter Maydell 515123ce4e3SPeter Maydell /* Catch the UNDEF cases. This is unavoidably a bit messy. */ 516123ce4e3SPeter Maydell switch (nregs) { 517123ce4e3SPeter Maydell case 1: 518123ce4e3SPeter Maydell if (((a->align & (1 << a->size)) != 0) || 519123ce4e3SPeter Maydell (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) { 520123ce4e3SPeter Maydell return false; 521123ce4e3SPeter Maydell } 522123ce4e3SPeter Maydell break; 523123ce4e3SPeter Maydell case 3: 524123ce4e3SPeter Maydell if ((a->align & 1) != 0) { 525123ce4e3SPeter Maydell return false; 526123ce4e3SPeter Maydell } 527123ce4e3SPeter Maydell /* fall through */ 528123ce4e3SPeter Maydell case 2: 529123ce4e3SPeter Maydell if (a->size == 2 && (a->align & 2) != 0) { 530123ce4e3SPeter Maydell return false; 531123ce4e3SPeter Maydell } 532123ce4e3SPeter Maydell break; 533123ce4e3SPeter Maydell case 4: 534123ce4e3SPeter Maydell if ((a->size == 2) && ((a->align & 3) == 3)) { 535123ce4e3SPeter Maydell return false; 536123ce4e3SPeter Maydell } 537123ce4e3SPeter Maydell break; 538123ce4e3SPeter Maydell default: 539123ce4e3SPeter Maydell abort(); 540123ce4e3SPeter Maydell } 541123ce4e3SPeter Maydell if ((vd + a->stride * (nregs - 1)) > 31) { 542123ce4e3SPeter Maydell /* 543123ce4e3SPeter Maydell * Attempts to write off the end of the register file are 544123ce4e3SPeter Maydell * UNPREDICTABLE; we choose to UNDEF because otherwise we would 545123ce4e3SPeter Maydell * access off the end of the array that holds the register data. 546123ce4e3SPeter Maydell */ 547123ce4e3SPeter Maydell return false; 548123ce4e3SPeter Maydell } 549123ce4e3SPeter Maydell 550123ce4e3SPeter Maydell if (!vfp_access_check(s)) { 551123ce4e3SPeter Maydell return true; 552123ce4e3SPeter Maydell } 553123ce4e3SPeter Maydell 554123ce4e3SPeter Maydell tmp = tcg_temp_new_i32(); 555123ce4e3SPeter Maydell addr = tcg_temp_new_i32(); 556123ce4e3SPeter Maydell load_reg_var(s, addr, a->rn); 557123ce4e3SPeter Maydell /* 558123ce4e3SPeter Maydell * TODO: if we implemented alignment exceptions, we should check 559123ce4e3SPeter Maydell * addr against the alignment encoded in a->align here. 560123ce4e3SPeter Maydell */ 561123ce4e3SPeter Maydell for (reg = 0; reg < nregs; reg++) { 562123ce4e3SPeter Maydell if (a->l) { 563123ce4e3SPeter Maydell gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), 564123ce4e3SPeter Maydell s->be_data | a->size); 565123ce4e3SPeter Maydell neon_store_element(vd, a->reg_idx, a->size, tmp); 566123ce4e3SPeter Maydell } else { /* Store */ 567123ce4e3SPeter Maydell neon_load_element(tmp, vd, a->reg_idx, a->size); 568123ce4e3SPeter Maydell gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), 569123ce4e3SPeter Maydell s->be_data | a->size); 570123ce4e3SPeter Maydell } 571123ce4e3SPeter Maydell vd += a->stride; 572123ce4e3SPeter Maydell tcg_gen_addi_i32(addr, addr, 1 << a->size); 573123ce4e3SPeter Maydell } 574123ce4e3SPeter Maydell tcg_temp_free_i32(addr); 575123ce4e3SPeter Maydell tcg_temp_free_i32(tmp); 576123ce4e3SPeter Maydell 577123ce4e3SPeter Maydell gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs); 578123ce4e3SPeter Maydell 579123ce4e3SPeter Maydell return true; 580123ce4e3SPeter Maydell } 581a4e143acSPeter Maydell 582a4e143acSPeter Maydell static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) 583a4e143acSPeter Maydell { 584a4e143acSPeter Maydell int vec_size = a->q ? 16 : 8; 585a4e143acSPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 586a4e143acSPeter Maydell int rn_ofs = neon_reg_offset(a->vn, 0); 587a4e143acSPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 588a4e143acSPeter Maydell 589a4e143acSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 590a4e143acSPeter Maydell return false; 591a4e143acSPeter Maydell } 592a4e143acSPeter Maydell 593a4e143acSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 594a4e143acSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 595a4e143acSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 596a4e143acSPeter Maydell return false; 597a4e143acSPeter Maydell } 598a4e143acSPeter Maydell 599a4e143acSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 600a4e143acSPeter Maydell return false; 601a4e143acSPeter Maydell } 602a4e143acSPeter Maydell 603a4e143acSPeter Maydell if (!vfp_access_check(s)) { 604a4e143acSPeter Maydell return true; 605a4e143acSPeter Maydell } 606a4e143acSPeter Maydell 607a4e143acSPeter Maydell fn(a->size, rd_ofs, rn_ofs, rm_ofs, vec_size, vec_size); 608a4e143acSPeter Maydell return true; 609a4e143acSPeter Maydell } 610a4e143acSPeter Maydell 611a4e143acSPeter Maydell #define DO_3SAME(INSN, FUNC) \ 612a4e143acSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 613a4e143acSPeter Maydell { \ 614a4e143acSPeter Maydell return do_3same(s, a, FUNC); \ 615a4e143acSPeter Maydell } 616a4e143acSPeter Maydell 617a4e143acSPeter Maydell DO_3SAME(VADD, tcg_gen_gvec_add) 618a4e143acSPeter Maydell DO_3SAME(VSUB, tcg_gen_gvec_sub) 61935a548edSPeter Maydell DO_3SAME(VAND, tcg_gen_gvec_and) 62035a548edSPeter Maydell DO_3SAME(VBIC, tcg_gen_gvec_andc) 62135a548edSPeter Maydell DO_3SAME(VORR, tcg_gen_gvec_or) 62235a548edSPeter Maydell DO_3SAME(VORN, tcg_gen_gvec_orc) 62335a548edSPeter Maydell DO_3SAME(VEOR, tcg_gen_gvec_xor) 6248161b753SRichard Henderson DO_3SAME(VSHL_S, gen_gvec_sshl) 6258161b753SRichard Henderson DO_3SAME(VSHL_U, gen_gvec_ushl) 626c7715b6bSRichard Henderson DO_3SAME(VQADD_S, gen_gvec_sqadd_qc) 627c7715b6bSRichard Henderson DO_3SAME(VQADD_U, gen_gvec_uqadd_qc) 628c7715b6bSRichard Henderson DO_3SAME(VQSUB_S, gen_gvec_sqsub_qc) 629c7715b6bSRichard Henderson DO_3SAME(VQSUB_U, gen_gvec_uqsub_qc) 63035a548edSPeter Maydell 63135a548edSPeter Maydell /* These insns are all gvec_bitsel but with the inputs in various orders. */ 63235a548edSPeter Maydell #define DO_3SAME_BITSEL(INSN, O1, O2, O3) \ 63335a548edSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 63435a548edSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 63535a548edSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 63635a548edSPeter Maydell { \ 63735a548edSPeter Maydell tcg_gen_gvec_bitsel(vece, rd_ofs, O1, O2, O3, oprsz, maxsz); \ 63835a548edSPeter Maydell } \ 63935a548edSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 64035a548edSPeter Maydell 64135a548edSPeter Maydell DO_3SAME_BITSEL(VBSL, rd_ofs, rn_ofs, rm_ofs) 64235a548edSPeter Maydell DO_3SAME_BITSEL(VBIT, rm_ofs, rn_ofs, rd_ofs) 64335a548edSPeter Maydell DO_3SAME_BITSEL(VBIF, rm_ofs, rd_ofs, rn_ofs) 64436b59310SPeter Maydell 64536b59310SPeter Maydell #define DO_3SAME_NO_SZ_3(INSN, FUNC) \ 64636b59310SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 64736b59310SPeter Maydell { \ 64836b59310SPeter Maydell if (a->size == 3) { \ 64936b59310SPeter Maydell return false; \ 65036b59310SPeter Maydell } \ 65136b59310SPeter Maydell return do_3same(s, a, FUNC); \ 65236b59310SPeter Maydell } 65336b59310SPeter Maydell 65436b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_S, tcg_gen_gvec_smax) 65536b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMAX_U, tcg_gen_gvec_umax) 65636b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_S, tcg_gen_gvec_smin) 65736b59310SPeter Maydell DO_3SAME_NO_SZ_3(VMIN_U, tcg_gen_gvec_umin) 6580de34fd4SPeter Maydell DO_3SAME_NO_SZ_3(VMUL, tcg_gen_gvec_mul) 65927106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLA, gen_gvec_mla) 66027106320SRichard Henderson DO_3SAME_NO_SZ_3(VMLS, gen_gvec_mls) 6618161b753SRichard Henderson DO_3SAME_NO_SZ_3(VTST, gen_gvec_cmtst) 6627715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_S, gen_gvec_sabd) 6637715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_S, gen_gvec_saba) 6647715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABD_U, gen_gvec_uabd) 6657715098fSPeter Maydell DO_3SAME_NO_SZ_3(VABA_U, gen_gvec_uaba) 66602bd0cdbSPeter Maydell 66702bd0cdbSPeter Maydell #define DO_3SAME_CMP(INSN, COND) \ 66802bd0cdbSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 66902bd0cdbSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 67002bd0cdbSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 67102bd0cdbSPeter Maydell { \ 67202bd0cdbSPeter Maydell tcg_gen_gvec_cmp(COND, vece, rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz); \ 67302bd0cdbSPeter Maydell } \ 67402bd0cdbSPeter Maydell DO_3SAME_NO_SZ_3(INSN, gen_##INSN##_3s) 67502bd0cdbSPeter Maydell 67602bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_S, TCG_COND_GT) 67702bd0cdbSPeter Maydell DO_3SAME_CMP(VCGT_U, TCG_COND_GTU) 67802bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_S, TCG_COND_GE) 67902bd0cdbSPeter Maydell DO_3SAME_CMP(VCGE_U, TCG_COND_GEU) 68002bd0cdbSPeter Maydell DO_3SAME_CMP(VCEQ, TCG_COND_EQ) 68102bd0cdbSPeter Maydell 682effa992fSRichard Henderson #define WRAP_OOL_FN(WRAPNAME, FUNC) \ 683effa992fSRichard Henderson static void WRAPNAME(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, \ 684effa992fSRichard Henderson uint32_t rm_ofs, uint32_t oprsz, uint32_t maxsz) \ 685effa992fSRichard Henderson { \ 686effa992fSRichard Henderson tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, 0, FUNC); \ 6870de34fd4SPeter Maydell } 6880de34fd4SPeter Maydell 689effa992fSRichard Henderson WRAP_OOL_FN(gen_VMUL_p_3s, gen_helper_gvec_pmul_b) 690effa992fSRichard Henderson 6910de34fd4SPeter Maydell static bool trans_VMUL_p_3s(DisasContext *s, arg_3same *a) 6920de34fd4SPeter Maydell { 6930de34fd4SPeter Maydell if (a->size != 0) { 6940de34fd4SPeter Maydell return false; 6950de34fd4SPeter Maydell } 6960de34fd4SPeter Maydell return do_3same(s, a, gen_VMUL_p_3s); 6970de34fd4SPeter Maydell } 698a0635695SPeter Maydell 699a0635695SPeter Maydell #define DO_VQRDMLAH(INSN, FUNC) \ 700a0635695SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 701a0635695SPeter Maydell { \ 702a0635695SPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { \ 703a0635695SPeter Maydell return false; \ 704a0635695SPeter Maydell } \ 705a0635695SPeter Maydell if (a->size != 1 && a->size != 2) { \ 706a0635695SPeter Maydell return false; \ 707a0635695SPeter Maydell } \ 708a0635695SPeter Maydell return do_3same(s, a, FUNC); \ 709a0635695SPeter Maydell } 710a0635695SPeter Maydell 711a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLAH, gen_gvec_sqrdmlah_qc) 712a0635695SPeter Maydell DO_VQRDMLAH(VQRDMLSH, gen_gvec_sqrdmlsh_qc) 71321290edfSPeter Maydell 714afc8b7d3SRichard Henderson #define DO_SHA1(NAME, FUNC) \ 715afc8b7d3SRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 716afc8b7d3SRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 717afc8b7d3SRichard Henderson { \ 718afc8b7d3SRichard Henderson if (!dc_isar_feature(aa32_sha1, s)) { \ 719afc8b7d3SRichard Henderson return false; \ 720afc8b7d3SRichard Henderson } \ 721afc8b7d3SRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 72221290edfSPeter Maydell } 72321290edfSPeter Maydell 724afc8b7d3SRichard Henderson DO_SHA1(SHA1C, gen_helper_crypto_sha1c) 725afc8b7d3SRichard Henderson DO_SHA1(SHA1P, gen_helper_crypto_sha1p) 726afc8b7d3SRichard Henderson DO_SHA1(SHA1M, gen_helper_crypto_sha1m) 727afc8b7d3SRichard Henderson DO_SHA1(SHA1SU0, gen_helper_crypto_sha1su0) 72821290edfSPeter Maydell 729effa992fSRichard Henderson #define DO_SHA2(NAME, FUNC) \ 730effa992fSRichard Henderson WRAP_OOL_FN(gen_##NAME##_3s, FUNC) \ 731effa992fSRichard Henderson static bool trans_##NAME##_3s(DisasContext *s, arg_3same *a) \ 732effa992fSRichard Henderson { \ 733effa992fSRichard Henderson if (!dc_isar_feature(aa32_sha2, s)) { \ 734effa992fSRichard Henderson return false; \ 735effa992fSRichard Henderson } \ 736effa992fSRichard Henderson return do_3same(s, a, gen_##NAME##_3s); \ 73721290edfSPeter Maydell } 73821290edfSPeter Maydell 739effa992fSRichard Henderson DO_SHA2(SHA256H, gen_helper_crypto_sha256h) 740effa992fSRichard Henderson DO_SHA2(SHA256H2, gen_helper_crypto_sha256h2) 741effa992fSRichard Henderson DO_SHA2(SHA256SU1, gen_helper_crypto_sha256su1) 74235d4352fSPeter Maydell 74335d4352fSPeter Maydell #define DO_3SAME_64(INSN, FUNC) \ 74435d4352fSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 74535d4352fSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 74635d4352fSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 74735d4352fSPeter Maydell { \ 74835d4352fSPeter Maydell static const GVecGen3 op = { .fni8 = FUNC }; \ 74935d4352fSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &op); \ 75035d4352fSPeter Maydell } \ 75135d4352fSPeter Maydell DO_3SAME(INSN, gen_##INSN##_3s) 75235d4352fSPeter Maydell 75335d4352fSPeter Maydell #define DO_3SAME_64_ENV(INSN, FUNC) \ 75435d4352fSPeter Maydell static void gen_##INSN##_elt(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m) \ 75535d4352fSPeter Maydell { \ 75635d4352fSPeter Maydell FUNC(d, cpu_env, n, m); \ 75735d4352fSPeter Maydell } \ 75835d4352fSPeter Maydell DO_3SAME_64(INSN, gen_##INSN##_elt) 75935d4352fSPeter Maydell 76035d4352fSPeter Maydell DO_3SAME_64(VRSHL_S64, gen_helper_neon_rshl_s64) 76135d4352fSPeter Maydell DO_3SAME_64(VRSHL_U64, gen_helper_neon_rshl_u64) 76235d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_S64, gen_helper_neon_qshl_s64) 76335d4352fSPeter Maydell DO_3SAME_64_ENV(VQSHL_U64, gen_helper_neon_qshl_u64) 76435d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_S64, gen_helper_neon_qrshl_s64) 76535d4352fSPeter Maydell DO_3SAME_64_ENV(VQRSHL_U64, gen_helper_neon_qrshl_u64) 766cb294bcaSPeter Maydell 767cb294bcaSPeter Maydell #define DO_3SAME_32(INSN, FUNC) \ 768cb294bcaSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 769cb294bcaSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 770cb294bcaSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 771cb294bcaSPeter Maydell { \ 772cb294bcaSPeter Maydell static const GVecGen3 ops[4] = { \ 773cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##8 }, \ 774cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##16 }, \ 775cb294bcaSPeter Maydell { .fni4 = gen_helper_neon_##FUNC##32 }, \ 776cb294bcaSPeter Maydell { 0 }, \ 777cb294bcaSPeter Maydell }; \ 778cb294bcaSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 779cb294bcaSPeter Maydell } \ 780cb294bcaSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 781cb294bcaSPeter Maydell { \ 782cb294bcaSPeter Maydell if (a->size > 2) { \ 783cb294bcaSPeter Maydell return false; \ 784cb294bcaSPeter Maydell } \ 785cb294bcaSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 786cb294bcaSPeter Maydell } 787cb294bcaSPeter Maydell 7886812dfdcSPeter Maydell /* 7896812dfdcSPeter Maydell * Some helper functions need to be passed the cpu_env. In order 7906812dfdcSPeter Maydell * to use those with the gvec APIs like tcg_gen_gvec_3() we need 7916812dfdcSPeter Maydell * to create wrapper functions whose prototype is a NeonGenTwoOpFn() 7926812dfdcSPeter Maydell * and which call a NeonGenTwoOpEnvFn(). 7936812dfdcSPeter Maydell */ 7946812dfdcSPeter Maydell #define WRAP_ENV_FN(WRAPNAME, FUNC) \ 7956812dfdcSPeter Maydell static void WRAPNAME(TCGv_i32 d, TCGv_i32 n, TCGv_i32 m) \ 7966812dfdcSPeter Maydell { \ 7976812dfdcSPeter Maydell FUNC(d, cpu_env, n, m); \ 7986812dfdcSPeter Maydell } 7996812dfdcSPeter Maydell 8006812dfdcSPeter Maydell #define DO_3SAME_32_ENV(INSN, FUNC) \ 8016812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp8, gen_helper_neon_##FUNC##8); \ 8026812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##16); \ 8036812dfdcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##32); \ 8046812dfdcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 8056812dfdcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 8066812dfdcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 8076812dfdcSPeter Maydell { \ 8086812dfdcSPeter Maydell static const GVecGen3 ops[4] = { \ 8096812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp8 }, \ 8106812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 8116812dfdcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 8126812dfdcSPeter Maydell { 0 }, \ 8136812dfdcSPeter Maydell }; \ 8146812dfdcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece]); \ 8156812dfdcSPeter Maydell } \ 8166812dfdcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 8176812dfdcSPeter Maydell { \ 8186812dfdcSPeter Maydell if (a->size > 2) { \ 8196812dfdcSPeter Maydell return false; \ 8206812dfdcSPeter Maydell } \ 8216812dfdcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 8226812dfdcSPeter Maydell } 8236812dfdcSPeter Maydell 824cb294bcaSPeter Maydell DO_3SAME_32(VHADD_S, hadd_s) 825cb294bcaSPeter Maydell DO_3SAME_32(VHADD_U, hadd_u) 8268e44d03fSPeter Maydell DO_3SAME_32(VHSUB_S, hsub_s) 8278e44d03fSPeter Maydell DO_3SAME_32(VHSUB_U, hsub_u) 8288e44d03fSPeter Maydell DO_3SAME_32(VRHADD_S, rhadd_s) 8298e44d03fSPeter Maydell DO_3SAME_32(VRHADD_U, rhadd_u) 8306812dfdcSPeter Maydell DO_3SAME_32(VRSHL_S, rshl_s) 8316812dfdcSPeter Maydell DO_3SAME_32(VRSHL_U, rshl_u) 8326812dfdcSPeter Maydell 8336812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_S, qshl_s) 8346812dfdcSPeter Maydell DO_3SAME_32_ENV(VQSHL_U, qshl_u) 8356812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_S, qrshl_s) 8366812dfdcSPeter Maydell DO_3SAME_32_ENV(VQRSHL_U, qrshl_u) 837059c2398SPeter Maydell 838059c2398SPeter Maydell static bool do_3same_pair(DisasContext *s, arg_3same *a, NeonGenTwoOpFn *fn) 839059c2398SPeter Maydell { 840059c2398SPeter Maydell /* Operations handled pairwise 32 bits at a time */ 841059c2398SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 842059c2398SPeter Maydell 843059c2398SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 844059c2398SPeter Maydell return false; 845059c2398SPeter Maydell } 846059c2398SPeter Maydell 847059c2398SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 848059c2398SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 849059c2398SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 850059c2398SPeter Maydell return false; 851059c2398SPeter Maydell } 852059c2398SPeter Maydell 853059c2398SPeter Maydell if (a->size == 3) { 854059c2398SPeter Maydell return false; 855059c2398SPeter Maydell } 856059c2398SPeter Maydell 857059c2398SPeter Maydell if (!vfp_access_check(s)) { 858059c2398SPeter Maydell return true; 859059c2398SPeter Maydell } 860059c2398SPeter Maydell 861059c2398SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 862059c2398SPeter Maydell 863059c2398SPeter Maydell /* 864059c2398SPeter Maydell * Note that we have to be careful not to clobber the source operands 865059c2398SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 866059c2398SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 867059c2398SPeter Maydell * of a complicated loop over each pass we just unroll. 868059c2398SPeter Maydell */ 869059c2398SPeter Maydell tmp = neon_load_reg(a->vn, 0); 870059c2398SPeter Maydell tmp2 = neon_load_reg(a->vn, 1); 871059c2398SPeter Maydell fn(tmp, tmp, tmp2); 872059c2398SPeter Maydell tcg_temp_free_i32(tmp2); 873059c2398SPeter Maydell 874059c2398SPeter Maydell tmp3 = neon_load_reg(a->vm, 0); 875059c2398SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 876059c2398SPeter Maydell fn(tmp3, tmp3, tmp2); 877059c2398SPeter Maydell tcg_temp_free_i32(tmp2); 878059c2398SPeter Maydell 879059c2398SPeter Maydell neon_store_reg(a->vd, 0, tmp); 880059c2398SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 881059c2398SPeter Maydell return true; 882059c2398SPeter Maydell } 883059c2398SPeter Maydell 884059c2398SPeter Maydell #define DO_3SAME_PAIR(INSN, func) \ 885059c2398SPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 886059c2398SPeter Maydell { \ 887059c2398SPeter Maydell static NeonGenTwoOpFn * const fns[] = { \ 888059c2398SPeter Maydell gen_helper_neon_##func##8, \ 889059c2398SPeter Maydell gen_helper_neon_##func##16, \ 890059c2398SPeter Maydell gen_helper_neon_##func##32, \ 891059c2398SPeter Maydell }; \ 892059c2398SPeter Maydell if (a->size > 2) { \ 893059c2398SPeter Maydell return false; \ 894059c2398SPeter Maydell } \ 895059c2398SPeter Maydell return do_3same_pair(s, a, fns[a->size]); \ 896059c2398SPeter Maydell } 897059c2398SPeter Maydell 898059c2398SPeter Maydell /* 32-bit pairwise ops end up the same as the elementwise versions. */ 899059c2398SPeter Maydell #define gen_helper_neon_pmax_s32 tcg_gen_smax_i32 900059c2398SPeter Maydell #define gen_helper_neon_pmax_u32 tcg_gen_umax_i32 901059c2398SPeter Maydell #define gen_helper_neon_pmin_s32 tcg_gen_smin_i32 902059c2398SPeter Maydell #define gen_helper_neon_pmin_u32 tcg_gen_umin_i32 903fa22827dSPeter Maydell #define gen_helper_neon_padd_u32 tcg_gen_add_i32 904059c2398SPeter Maydell 905059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_S, pmax_s) 906059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_S, pmin_s) 907059c2398SPeter Maydell DO_3SAME_PAIR(VPMAX_U, pmax_u) 908059c2398SPeter Maydell DO_3SAME_PAIR(VPMIN_U, pmin_u) 909fa22827dSPeter Maydell DO_3SAME_PAIR(VPADD, padd_u) 9107ecc28bcSPeter Maydell 9117ecc28bcSPeter Maydell #define DO_3SAME_VQDMULH(INSN, FUNC) \ 9127ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp16, gen_helper_neon_##FUNC##_s16); \ 9137ecc28bcSPeter Maydell WRAP_ENV_FN(gen_##INSN##_tramp32, gen_helper_neon_##FUNC##_s32); \ 9147ecc28bcSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 9157ecc28bcSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 9167ecc28bcSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 9177ecc28bcSPeter Maydell { \ 9187ecc28bcSPeter Maydell static const GVecGen3 ops[2] = { \ 9197ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp16 }, \ 9207ecc28bcSPeter Maydell { .fni4 = gen_##INSN##_tramp32 }, \ 9217ecc28bcSPeter Maydell }; \ 9227ecc28bcSPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops[vece - 1]); \ 9237ecc28bcSPeter Maydell } \ 9247ecc28bcSPeter Maydell static bool trans_##INSN##_3s(DisasContext *s, arg_3same *a) \ 9257ecc28bcSPeter Maydell { \ 9267ecc28bcSPeter Maydell if (a->size != 1 && a->size != 2) { \ 9277ecc28bcSPeter Maydell return false; \ 9287ecc28bcSPeter Maydell } \ 9297ecc28bcSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 9307ecc28bcSPeter Maydell } 9317ecc28bcSPeter Maydell 9327ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQDMULH, qdmulh) 9337ecc28bcSPeter Maydell DO_3SAME_VQDMULH(VQRDMULH, qrdmulh) 934a26a352bSPeter Maydell 9358aa71eadSPeter Maydell static bool do_3same_fp(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn, 9368aa71eadSPeter Maydell bool reads_vd) 9378aa71eadSPeter Maydell { 9388aa71eadSPeter Maydell /* 9398aa71eadSPeter Maydell * FP operations handled elementwise 32 bits at a time. 9408aa71eadSPeter Maydell * If reads_vd is true then the old value of Vd will be 9418aa71eadSPeter Maydell * loaded before calling the callback function. This is 9428aa71eadSPeter Maydell * used for multiply-accumulate type operations. 9438aa71eadSPeter Maydell */ 9448aa71eadSPeter Maydell TCGv_i32 tmp, tmp2; 9458aa71eadSPeter Maydell int pass; 9468aa71eadSPeter Maydell 9478aa71eadSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 9488aa71eadSPeter Maydell return false; 9498aa71eadSPeter Maydell } 9508aa71eadSPeter Maydell 9518aa71eadSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 9528aa71eadSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 9538aa71eadSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 9548aa71eadSPeter Maydell return false; 9558aa71eadSPeter Maydell } 9568aa71eadSPeter Maydell 9578aa71eadSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 9588aa71eadSPeter Maydell return false; 9598aa71eadSPeter Maydell } 9608aa71eadSPeter Maydell 9618aa71eadSPeter Maydell if (!vfp_access_check(s)) { 9628aa71eadSPeter Maydell return true; 9638aa71eadSPeter Maydell } 9648aa71eadSPeter Maydell 9658aa71eadSPeter Maydell TCGv_ptr fpstatus = get_fpstatus_ptr(1); 9668aa71eadSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 9678aa71eadSPeter Maydell tmp = neon_load_reg(a->vn, pass); 9688aa71eadSPeter Maydell tmp2 = neon_load_reg(a->vm, pass); 9698aa71eadSPeter Maydell if (reads_vd) { 9708aa71eadSPeter Maydell TCGv_i32 tmp_rd = neon_load_reg(a->vd, pass); 9718aa71eadSPeter Maydell fn(tmp_rd, tmp, tmp2, fpstatus); 9728aa71eadSPeter Maydell neon_store_reg(a->vd, pass, tmp_rd); 9738aa71eadSPeter Maydell tcg_temp_free_i32(tmp); 9748aa71eadSPeter Maydell } else { 9758aa71eadSPeter Maydell fn(tmp, tmp, tmp2, fpstatus); 9768aa71eadSPeter Maydell neon_store_reg(a->vd, pass, tmp); 9778aa71eadSPeter Maydell } 9788aa71eadSPeter Maydell tcg_temp_free_i32(tmp2); 9798aa71eadSPeter Maydell } 9808aa71eadSPeter Maydell tcg_temp_free_ptr(fpstatus); 9818aa71eadSPeter Maydell return true; 9828aa71eadSPeter Maydell } 9838aa71eadSPeter Maydell 984a26a352bSPeter Maydell /* 985a26a352bSPeter Maydell * For all the functions using this macro, size == 1 means fp16, 986a26a352bSPeter Maydell * which is an architecture extension we don't implement yet. 987a26a352bSPeter Maydell */ 988a26a352bSPeter Maydell #define DO_3S_FP_GVEC(INSN,FUNC) \ 989a26a352bSPeter Maydell static void gen_##INSN##_3s(unsigned vece, uint32_t rd_ofs, \ 990a26a352bSPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, \ 991a26a352bSPeter Maydell uint32_t oprsz, uint32_t maxsz) \ 992a26a352bSPeter Maydell { \ 993a26a352bSPeter Maydell TCGv_ptr fpst = get_fpstatus_ptr(1); \ 994a26a352bSPeter Maydell tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, fpst, \ 995a26a352bSPeter Maydell oprsz, maxsz, 0, FUNC); \ 996a26a352bSPeter Maydell tcg_temp_free_ptr(fpst); \ 997a26a352bSPeter Maydell } \ 998a26a352bSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 999a26a352bSPeter Maydell { \ 1000a26a352bSPeter Maydell if (a->size != 0) { \ 1001a26a352bSPeter Maydell /* TODO fp16 support */ \ 1002a26a352bSPeter Maydell return false; \ 1003a26a352bSPeter Maydell } \ 1004a26a352bSPeter Maydell return do_3same(s, a, gen_##INSN##_3s); \ 1005a26a352bSPeter Maydell } 1006a26a352bSPeter Maydell 1007a26a352bSPeter Maydell 1008a26a352bSPeter Maydell DO_3S_FP_GVEC(VADD, gen_helper_gvec_fadd_s) 1009a26a352bSPeter Maydell DO_3S_FP_GVEC(VSUB, gen_helper_gvec_fsub_s) 1010a26a352bSPeter Maydell DO_3S_FP_GVEC(VABD, gen_helper_gvec_fabd_s) 10118aa71eadSPeter Maydell DO_3S_FP_GVEC(VMUL, gen_helper_gvec_fmul_s) 10128aa71eadSPeter Maydell 10138aa71eadSPeter Maydell /* 10148aa71eadSPeter Maydell * For all the functions using this macro, size == 1 means fp16, 10158aa71eadSPeter Maydell * which is an architecture extension we don't implement yet. 10168aa71eadSPeter Maydell */ 10178aa71eadSPeter Maydell #define DO_3S_FP(INSN,FUNC,READS_VD) \ 10188aa71eadSPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 10198aa71eadSPeter Maydell { \ 10208aa71eadSPeter Maydell if (a->size != 0) { \ 10218aa71eadSPeter Maydell /* TODO fp16 support */ \ 10228aa71eadSPeter Maydell return false; \ 10238aa71eadSPeter Maydell } \ 10248aa71eadSPeter Maydell return do_3same_fp(s, a, FUNC, READS_VD); \ 10258aa71eadSPeter Maydell } 10268aa71eadSPeter Maydell 1027727ff1d6SPeter Maydell DO_3S_FP(VCEQ, gen_helper_neon_ceq_f32, false) 1028727ff1d6SPeter Maydell DO_3S_FP(VCGE, gen_helper_neon_cge_f32, false) 1029727ff1d6SPeter Maydell DO_3S_FP(VCGT, gen_helper_neon_cgt_f32, false) 1030727ff1d6SPeter Maydell DO_3S_FP(VACGE, gen_helper_neon_acge_f32, false) 1031727ff1d6SPeter Maydell DO_3S_FP(VACGT, gen_helper_neon_acgt_f32, false) 1032d5fdf9e9SPeter Maydell DO_3S_FP(VMAX, gen_helper_vfp_maxs, false) 1033d5fdf9e9SPeter Maydell DO_3S_FP(VMIN, gen_helper_vfp_mins, false) 1034727ff1d6SPeter Maydell 10358aa71eadSPeter Maydell static void gen_VMLA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 10368aa71eadSPeter Maydell TCGv_ptr fpstatus) 10378aa71eadSPeter Maydell { 10388aa71eadSPeter Maydell gen_helper_vfp_muls(vn, vn, vm, fpstatus); 10398aa71eadSPeter Maydell gen_helper_vfp_adds(vd, vd, vn, fpstatus); 10408aa71eadSPeter Maydell } 10418aa71eadSPeter Maydell 10428aa71eadSPeter Maydell static void gen_VMLS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 10438aa71eadSPeter Maydell TCGv_ptr fpstatus) 10448aa71eadSPeter Maydell { 10458aa71eadSPeter Maydell gen_helper_vfp_muls(vn, vn, vm, fpstatus); 10468aa71eadSPeter Maydell gen_helper_vfp_subs(vd, vd, vn, fpstatus); 10478aa71eadSPeter Maydell } 10488aa71eadSPeter Maydell 10498aa71eadSPeter Maydell DO_3S_FP(VMLA, gen_VMLA_fp_3s, true) 10508aa71eadSPeter Maydell DO_3S_FP(VMLS, gen_VMLS_fp_3s, true) 1051ab978335SPeter Maydell 1052d5fdf9e9SPeter Maydell static bool trans_VMAXNM_fp_3s(DisasContext *s, arg_3same *a) 1053d5fdf9e9SPeter Maydell { 1054d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1055d5fdf9e9SPeter Maydell return false; 1056d5fdf9e9SPeter Maydell } 1057d5fdf9e9SPeter Maydell 1058d5fdf9e9SPeter Maydell if (a->size != 0) { 1059d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1060d5fdf9e9SPeter Maydell return false; 1061d5fdf9e9SPeter Maydell } 1062d5fdf9e9SPeter Maydell 1063d5fdf9e9SPeter Maydell return do_3same_fp(s, a, gen_helper_vfp_maxnums, false); 1064d5fdf9e9SPeter Maydell } 1065d5fdf9e9SPeter Maydell 1066d5fdf9e9SPeter Maydell static bool trans_VMINNM_fp_3s(DisasContext *s, arg_3same *a) 1067d5fdf9e9SPeter Maydell { 1068d5fdf9e9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_V8)) { 1069d5fdf9e9SPeter Maydell return false; 1070d5fdf9e9SPeter Maydell } 1071d5fdf9e9SPeter Maydell 1072d5fdf9e9SPeter Maydell if (a->size != 0) { 1073d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1074d5fdf9e9SPeter Maydell return false; 1075d5fdf9e9SPeter Maydell } 1076d5fdf9e9SPeter Maydell 1077d5fdf9e9SPeter Maydell return do_3same_fp(s, a, gen_helper_vfp_minnums, false); 1078d5fdf9e9SPeter Maydell } 1079d5fdf9e9SPeter Maydell 1080d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRECPS_tramp, gen_helper_recps_f32) 1081d5fdf9e9SPeter Maydell 1082d5fdf9e9SPeter Maydell static void gen_VRECPS_fp_3s(unsigned vece, uint32_t rd_ofs, 1083d5fdf9e9SPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, 1084d5fdf9e9SPeter Maydell uint32_t oprsz, uint32_t maxsz) 1085d5fdf9e9SPeter Maydell { 1086d5fdf9e9SPeter Maydell static const GVecGen3 ops = { .fni4 = gen_VRECPS_tramp }; 1087d5fdf9e9SPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); 1088d5fdf9e9SPeter Maydell } 1089d5fdf9e9SPeter Maydell 1090d5fdf9e9SPeter Maydell static bool trans_VRECPS_fp_3s(DisasContext *s, arg_3same *a) 1091d5fdf9e9SPeter Maydell { 1092d5fdf9e9SPeter Maydell if (a->size != 0) { 1093d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1094d5fdf9e9SPeter Maydell return false; 1095d5fdf9e9SPeter Maydell } 1096d5fdf9e9SPeter Maydell 1097d5fdf9e9SPeter Maydell return do_3same(s, a, gen_VRECPS_fp_3s); 1098d5fdf9e9SPeter Maydell } 1099d5fdf9e9SPeter Maydell 1100d5fdf9e9SPeter Maydell WRAP_ENV_FN(gen_VRSQRTS_tramp, gen_helper_rsqrts_f32) 1101d5fdf9e9SPeter Maydell 1102d5fdf9e9SPeter Maydell static void gen_VRSQRTS_fp_3s(unsigned vece, uint32_t rd_ofs, 1103d5fdf9e9SPeter Maydell uint32_t rn_ofs, uint32_t rm_ofs, 1104d5fdf9e9SPeter Maydell uint32_t oprsz, uint32_t maxsz) 1105d5fdf9e9SPeter Maydell { 1106d5fdf9e9SPeter Maydell static const GVecGen3 ops = { .fni4 = gen_VRSQRTS_tramp }; 1107d5fdf9e9SPeter Maydell tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, oprsz, maxsz, &ops); 1108d5fdf9e9SPeter Maydell } 1109d5fdf9e9SPeter Maydell 1110d5fdf9e9SPeter Maydell static bool trans_VRSQRTS_fp_3s(DisasContext *s, arg_3same *a) 1111d5fdf9e9SPeter Maydell { 1112d5fdf9e9SPeter Maydell if (a->size != 0) { 1113d5fdf9e9SPeter Maydell /* TODO fp16 support */ 1114d5fdf9e9SPeter Maydell return false; 1115d5fdf9e9SPeter Maydell } 1116d5fdf9e9SPeter Maydell 1117d5fdf9e9SPeter Maydell return do_3same(s, a, gen_VRSQRTS_fp_3s); 1118d5fdf9e9SPeter Maydell } 1119d5fdf9e9SPeter Maydell 1120e95485f8SPeter Maydell static void gen_VFMA_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 1121e95485f8SPeter Maydell TCGv_ptr fpstatus) 1122e95485f8SPeter Maydell { 1123e95485f8SPeter Maydell gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); 1124e95485f8SPeter Maydell } 1125e95485f8SPeter Maydell 1126e95485f8SPeter Maydell static bool trans_VFMA_fp_3s(DisasContext *s, arg_3same *a) 1127e95485f8SPeter Maydell { 1128e95485f8SPeter Maydell if (!dc_isar_feature(aa32_simdfmac, s)) { 1129e95485f8SPeter Maydell return false; 1130e95485f8SPeter Maydell } 1131e95485f8SPeter Maydell 1132e95485f8SPeter Maydell if (a->size != 0) { 1133e95485f8SPeter Maydell /* TODO fp16 support */ 1134e95485f8SPeter Maydell return false; 1135e95485f8SPeter Maydell } 1136e95485f8SPeter Maydell 1137e95485f8SPeter Maydell return do_3same_fp(s, a, gen_VFMA_fp_3s, true); 1138e95485f8SPeter Maydell } 1139e95485f8SPeter Maydell 1140e95485f8SPeter Maydell static void gen_VFMS_fp_3s(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, 1141e95485f8SPeter Maydell TCGv_ptr fpstatus) 1142e95485f8SPeter Maydell { 1143e95485f8SPeter Maydell gen_helper_vfp_negs(vn, vn); 1144e95485f8SPeter Maydell gen_helper_vfp_muladds(vd, vn, vm, vd, fpstatus); 1145e95485f8SPeter Maydell } 1146e95485f8SPeter Maydell 1147e95485f8SPeter Maydell static bool trans_VFMS_fp_3s(DisasContext *s, arg_3same *a) 1148e95485f8SPeter Maydell { 1149e95485f8SPeter Maydell if (!dc_isar_feature(aa32_simdfmac, s)) { 1150e95485f8SPeter Maydell return false; 1151e95485f8SPeter Maydell } 1152e95485f8SPeter Maydell 1153e95485f8SPeter Maydell if (a->size != 0) { 1154e95485f8SPeter Maydell /* TODO fp16 support */ 1155e95485f8SPeter Maydell return false; 1156e95485f8SPeter Maydell } 1157e95485f8SPeter Maydell 1158e95485f8SPeter Maydell return do_3same_fp(s, a, gen_VFMS_fp_3s, true); 1159e95485f8SPeter Maydell } 1160e95485f8SPeter Maydell 1161ab978335SPeter Maydell static bool do_3same_fp_pair(DisasContext *s, arg_3same *a, VFPGen3OpSPFn *fn) 1162ab978335SPeter Maydell { 1163ab978335SPeter Maydell /* FP operations handled pairwise 32 bits at a time */ 1164ab978335SPeter Maydell TCGv_i32 tmp, tmp2, tmp3; 1165ab978335SPeter Maydell TCGv_ptr fpstatus; 1166ab978335SPeter Maydell 1167ab978335SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1168ab978335SPeter Maydell return false; 1169ab978335SPeter Maydell } 1170ab978335SPeter Maydell 1171ab978335SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1172ab978335SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1173ab978335SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1174ab978335SPeter Maydell return false; 1175ab978335SPeter Maydell } 1176ab978335SPeter Maydell 1177ab978335SPeter Maydell if (!vfp_access_check(s)) { 1178ab978335SPeter Maydell return true; 1179ab978335SPeter Maydell } 1180ab978335SPeter Maydell 1181ab978335SPeter Maydell assert(a->q == 0); /* enforced by decode patterns */ 1182ab978335SPeter Maydell 1183ab978335SPeter Maydell /* 1184ab978335SPeter Maydell * Note that we have to be careful not to clobber the source operands 1185ab978335SPeter Maydell * in the "vm == vd" case by storing the result of the first pass too 1186ab978335SPeter Maydell * early. Since Q is 0 there are always just two passes, so instead 1187ab978335SPeter Maydell * of a complicated loop over each pass we just unroll. 1188ab978335SPeter Maydell */ 1189ab978335SPeter Maydell fpstatus = get_fpstatus_ptr(1); 1190ab978335SPeter Maydell tmp = neon_load_reg(a->vn, 0); 1191ab978335SPeter Maydell tmp2 = neon_load_reg(a->vn, 1); 1192ab978335SPeter Maydell fn(tmp, tmp, tmp2, fpstatus); 1193ab978335SPeter Maydell tcg_temp_free_i32(tmp2); 1194ab978335SPeter Maydell 1195ab978335SPeter Maydell tmp3 = neon_load_reg(a->vm, 0); 1196ab978335SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 1197ab978335SPeter Maydell fn(tmp3, tmp3, tmp2, fpstatus); 1198ab978335SPeter Maydell tcg_temp_free_i32(tmp2); 1199ab978335SPeter Maydell tcg_temp_free_ptr(fpstatus); 1200ab978335SPeter Maydell 1201ab978335SPeter Maydell neon_store_reg(a->vd, 0, tmp); 1202ab978335SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 1203ab978335SPeter Maydell return true; 1204ab978335SPeter Maydell } 1205ab978335SPeter Maydell 1206ab978335SPeter Maydell /* 1207ab978335SPeter Maydell * For all the functions using this macro, size == 1 means fp16, 1208ab978335SPeter Maydell * which is an architecture extension we don't implement yet. 1209ab978335SPeter Maydell */ 1210ab978335SPeter Maydell #define DO_3S_FP_PAIR(INSN,FUNC) \ 1211ab978335SPeter Maydell static bool trans_##INSN##_fp_3s(DisasContext *s, arg_3same *a) \ 1212ab978335SPeter Maydell { \ 1213ab978335SPeter Maydell if (a->size != 0) { \ 1214ab978335SPeter Maydell /* TODO fp16 support */ \ 1215ab978335SPeter Maydell return false; \ 1216ab978335SPeter Maydell } \ 1217ab978335SPeter Maydell return do_3same_fp_pair(s, a, FUNC); \ 1218ab978335SPeter Maydell } 1219ab978335SPeter Maydell 1220ab978335SPeter Maydell DO_3S_FP_PAIR(VPADD, gen_helper_vfp_adds) 1221ab978335SPeter Maydell DO_3S_FP_PAIR(VPMAX, gen_helper_vfp_maxs) 1222ab978335SPeter Maydell DO_3S_FP_PAIR(VPMIN, gen_helper_vfp_mins) 1223d3c8c736SPeter Maydell 1224d3c8c736SPeter Maydell static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) 1225d3c8c736SPeter Maydell { 1226d3c8c736SPeter Maydell /* Handle a 2-reg-shift insn which can be vectorized. */ 1227d3c8c736SPeter Maydell int vec_size = a->q ? 16 : 8; 1228d3c8c736SPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 1229d3c8c736SPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 1230d3c8c736SPeter Maydell 1231d3c8c736SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1232d3c8c736SPeter Maydell return false; 1233d3c8c736SPeter Maydell } 1234d3c8c736SPeter Maydell 1235d3c8c736SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1236d3c8c736SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1237d3c8c736SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1238d3c8c736SPeter Maydell return false; 1239d3c8c736SPeter Maydell } 1240d3c8c736SPeter Maydell 1241d3c8c736SPeter Maydell if ((a->vm | a->vd) & a->q) { 1242d3c8c736SPeter Maydell return false; 1243d3c8c736SPeter Maydell } 1244d3c8c736SPeter Maydell 1245d3c8c736SPeter Maydell if (!vfp_access_check(s)) { 1246d3c8c736SPeter Maydell return true; 1247d3c8c736SPeter Maydell } 1248d3c8c736SPeter Maydell 1249d3c8c736SPeter Maydell fn(a->size, rd_ofs, rm_ofs, a->shift, vec_size, vec_size); 1250d3c8c736SPeter Maydell return true; 1251d3c8c736SPeter Maydell } 1252d3c8c736SPeter Maydell 1253d3c8c736SPeter Maydell #define DO_2SH(INSN, FUNC) \ 1254d3c8c736SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1255d3c8c736SPeter Maydell { \ 1256d3c8c736SPeter Maydell return do_vector_2sh(s, a, FUNC); \ 1257d3c8c736SPeter Maydell } \ 1258d3c8c736SPeter Maydell 1259d3c8c736SPeter Maydell DO_2SH(VSHL, tcg_gen_gvec_shli) 1260d3c8c736SPeter Maydell DO_2SH(VSLI, gen_gvec_sli) 1261434f71efSPeter Maydell DO_2SH(VSRI, gen_gvec_sri) 1262434f71efSPeter Maydell DO_2SH(VSRA_S, gen_gvec_ssra) 1263434f71efSPeter Maydell DO_2SH(VSRA_U, gen_gvec_usra) 1264434f71efSPeter Maydell DO_2SH(VRSHR_S, gen_gvec_srshr) 1265434f71efSPeter Maydell DO_2SH(VRSHR_U, gen_gvec_urshr) 1266434f71efSPeter Maydell DO_2SH(VRSRA_S, gen_gvec_srsra) 1267434f71efSPeter Maydell DO_2SH(VRSRA_U, gen_gvec_ursra) 126866432d6bSPeter Maydell 126966432d6bSPeter Maydell static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a) 127066432d6bSPeter Maydell { 127166432d6bSPeter Maydell /* Signed shift out of range results in all-sign-bits */ 127266432d6bSPeter Maydell a->shift = MIN(a->shift, (8 << a->size) - 1); 127366432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_sari); 127466432d6bSPeter Maydell } 127566432d6bSPeter Maydell 127666432d6bSPeter Maydell static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, 127766432d6bSPeter Maydell int64_t shift, uint32_t oprsz, uint32_t maxsz) 127866432d6bSPeter Maydell { 127966432d6bSPeter Maydell tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0); 128066432d6bSPeter Maydell } 128166432d6bSPeter Maydell 128266432d6bSPeter Maydell static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a) 128366432d6bSPeter Maydell { 128466432d6bSPeter Maydell /* Shift out of range is architecturally valid and results in zero. */ 128566432d6bSPeter Maydell if (a->shift >= (8 << a->size)) { 128666432d6bSPeter Maydell return do_vector_2sh(s, a, gen_zero_rd_2sh); 128766432d6bSPeter Maydell } else { 128866432d6bSPeter Maydell return do_vector_2sh(s, a, tcg_gen_gvec_shri); 128966432d6bSPeter Maydell } 129066432d6bSPeter Maydell } 129137bfce81SPeter Maydell 129237bfce81SPeter Maydell static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a, 129337bfce81SPeter Maydell NeonGenTwo64OpEnvFn *fn) 129437bfce81SPeter Maydell { 129537bfce81SPeter Maydell /* 129637bfce81SPeter Maydell * 2-reg-and-shift operations, size == 3 case, where the 129737bfce81SPeter Maydell * function needs to be passed cpu_env. 129837bfce81SPeter Maydell */ 129937bfce81SPeter Maydell TCGv_i64 constimm; 130037bfce81SPeter Maydell int pass; 130137bfce81SPeter Maydell 130237bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 130337bfce81SPeter Maydell return false; 130437bfce81SPeter Maydell } 130537bfce81SPeter Maydell 130637bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 130737bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 130837bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 130937bfce81SPeter Maydell return false; 131037bfce81SPeter Maydell } 131137bfce81SPeter Maydell 131237bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 131337bfce81SPeter Maydell return false; 131437bfce81SPeter Maydell } 131537bfce81SPeter Maydell 131637bfce81SPeter Maydell if (!vfp_access_check(s)) { 131737bfce81SPeter Maydell return true; 131837bfce81SPeter Maydell } 131937bfce81SPeter Maydell 132037bfce81SPeter Maydell /* 132137bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 132237bfce81SPeter Maydell * by immediate using the variable shift operations. 132337bfce81SPeter Maydell */ 132437bfce81SPeter Maydell constimm = tcg_const_i64(dup_const(a->size, a->shift)); 132537bfce81SPeter Maydell 132637bfce81SPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 132737bfce81SPeter Maydell TCGv_i64 tmp = tcg_temp_new_i64(); 132837bfce81SPeter Maydell 132937bfce81SPeter Maydell neon_load_reg64(tmp, a->vm + pass); 133037bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 133137bfce81SPeter Maydell neon_store_reg64(tmp, a->vd + pass); 1332a4f67e18SPeter Maydell tcg_temp_free_i64(tmp); 133337bfce81SPeter Maydell } 133437bfce81SPeter Maydell tcg_temp_free_i64(constimm); 133537bfce81SPeter Maydell return true; 133637bfce81SPeter Maydell } 133737bfce81SPeter Maydell 133837bfce81SPeter Maydell static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a, 133937bfce81SPeter Maydell NeonGenTwoOpEnvFn *fn) 134037bfce81SPeter Maydell { 134137bfce81SPeter Maydell /* 134237bfce81SPeter Maydell * 2-reg-and-shift operations, size < 3 case, where the 134337bfce81SPeter Maydell * helper needs to be passed cpu_env. 134437bfce81SPeter Maydell */ 134537bfce81SPeter Maydell TCGv_i32 constimm; 134637bfce81SPeter Maydell int pass; 134737bfce81SPeter Maydell 134837bfce81SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 134937bfce81SPeter Maydell return false; 135037bfce81SPeter Maydell } 135137bfce81SPeter Maydell 135237bfce81SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 135337bfce81SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 135437bfce81SPeter Maydell ((a->vd | a->vm) & 0x10)) { 135537bfce81SPeter Maydell return false; 135637bfce81SPeter Maydell } 135737bfce81SPeter Maydell 135837bfce81SPeter Maydell if ((a->vm | a->vd) & a->q) { 135937bfce81SPeter Maydell return false; 136037bfce81SPeter Maydell } 136137bfce81SPeter Maydell 136237bfce81SPeter Maydell if (!vfp_access_check(s)) { 136337bfce81SPeter Maydell return true; 136437bfce81SPeter Maydell } 136537bfce81SPeter Maydell 136637bfce81SPeter Maydell /* 136737bfce81SPeter Maydell * To avoid excessive duplication of ops we implement shift 136837bfce81SPeter Maydell * by immediate using the variable shift operations. 136937bfce81SPeter Maydell */ 137037bfce81SPeter Maydell constimm = tcg_const_i32(dup_const(a->size, a->shift)); 137137bfce81SPeter Maydell 137237bfce81SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 137337bfce81SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vm, pass); 137437bfce81SPeter Maydell fn(tmp, cpu_env, tmp, constimm); 137537bfce81SPeter Maydell neon_store_reg(a->vd, pass, tmp); 137637bfce81SPeter Maydell } 137737bfce81SPeter Maydell tcg_temp_free_i32(constimm); 137837bfce81SPeter Maydell return true; 137937bfce81SPeter Maydell } 138037bfce81SPeter Maydell 138137bfce81SPeter Maydell #define DO_2SHIFT_ENV(INSN, FUNC) \ 138237bfce81SPeter Maydell static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \ 138337bfce81SPeter Maydell { \ 138437bfce81SPeter Maydell return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \ 138537bfce81SPeter Maydell } \ 138637bfce81SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 138737bfce81SPeter Maydell { \ 138837bfce81SPeter Maydell static NeonGenTwoOpEnvFn * const fns[] = { \ 138937bfce81SPeter Maydell gen_helper_neon_##FUNC##8, \ 139037bfce81SPeter Maydell gen_helper_neon_##FUNC##16, \ 139137bfce81SPeter Maydell gen_helper_neon_##FUNC##32, \ 139237bfce81SPeter Maydell }; \ 139337bfce81SPeter Maydell assert(a->size < ARRAY_SIZE(fns)); \ 139437bfce81SPeter Maydell return do_2shift_env_32(s, a, fns[a->size]); \ 139537bfce81SPeter Maydell } 139637bfce81SPeter Maydell 139737bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHLU, qshlu_s) 139837bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_U, qshl_u) 139937bfce81SPeter Maydell DO_2SHIFT_ENV(VQSHL_S, qshl_s) 1400712182d3SPeter Maydell 1401712182d3SPeter Maydell static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, 1402712182d3SPeter Maydell NeonGenTwo64OpFn *shiftfn, 1403712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1404712182d3SPeter Maydell { 1405712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size == 3 case */ 1406712182d3SPeter Maydell TCGv_i64 constimm, rm1, rm2; 1407712182d3SPeter Maydell TCGv_i32 rd; 1408712182d3SPeter Maydell 1409712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1410712182d3SPeter Maydell return false; 1411712182d3SPeter Maydell } 1412712182d3SPeter Maydell 1413712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1414712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1415712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1416712182d3SPeter Maydell return false; 1417712182d3SPeter Maydell } 1418712182d3SPeter Maydell 1419712182d3SPeter Maydell if (a->vm & 1) { 1420712182d3SPeter Maydell return false; 1421712182d3SPeter Maydell } 1422712182d3SPeter Maydell 1423712182d3SPeter Maydell if (!vfp_access_check(s)) { 1424712182d3SPeter Maydell return true; 1425712182d3SPeter Maydell } 1426712182d3SPeter Maydell 1427712182d3SPeter Maydell /* 1428712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1429712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count. 1430712182d3SPeter Maydell */ 1431712182d3SPeter Maydell constimm = tcg_const_i64(-a->shift); 1432712182d3SPeter Maydell rm1 = tcg_temp_new_i64(); 1433712182d3SPeter Maydell rm2 = tcg_temp_new_i64(); 1434712182d3SPeter Maydell 1435712182d3SPeter Maydell /* Load both inputs first to avoid potential overwrite if rm == rd */ 1436712182d3SPeter Maydell neon_load_reg64(rm1, a->vm); 1437712182d3SPeter Maydell neon_load_reg64(rm2, a->vm + 1); 1438712182d3SPeter Maydell 1439712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1440712182d3SPeter Maydell rd = tcg_temp_new_i32(); 1441712182d3SPeter Maydell narrowfn(rd, cpu_env, rm1); 1442712182d3SPeter Maydell neon_store_reg(a->vd, 0, rd); 1443712182d3SPeter Maydell 1444712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1445712182d3SPeter Maydell rd = tcg_temp_new_i32(); 1446712182d3SPeter Maydell narrowfn(rd, cpu_env, rm2); 1447712182d3SPeter Maydell neon_store_reg(a->vd, 1, rd); 1448712182d3SPeter Maydell 1449712182d3SPeter Maydell tcg_temp_free_i64(rm1); 1450712182d3SPeter Maydell tcg_temp_free_i64(rm2); 1451712182d3SPeter Maydell tcg_temp_free_i64(constimm); 1452712182d3SPeter Maydell 1453712182d3SPeter Maydell return true; 1454712182d3SPeter Maydell } 1455712182d3SPeter Maydell 1456712182d3SPeter Maydell static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, 1457712182d3SPeter Maydell NeonGenTwoOpFn *shiftfn, 1458712182d3SPeter Maydell NeonGenNarrowEnvFn *narrowfn) 1459712182d3SPeter Maydell { 1460712182d3SPeter Maydell /* 2-reg-and-shift narrowing-shift operations, size < 3 case */ 1461712182d3SPeter Maydell TCGv_i32 constimm, rm1, rm2, rm3, rm4; 1462712182d3SPeter Maydell TCGv_i64 rtmp; 1463712182d3SPeter Maydell uint32_t imm; 1464712182d3SPeter Maydell 1465712182d3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1466712182d3SPeter Maydell return false; 1467712182d3SPeter Maydell } 1468712182d3SPeter Maydell 1469712182d3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1470712182d3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1471712182d3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1472712182d3SPeter Maydell return false; 1473712182d3SPeter Maydell } 1474712182d3SPeter Maydell 1475712182d3SPeter Maydell if (a->vm & 1) { 1476712182d3SPeter Maydell return false; 1477712182d3SPeter Maydell } 1478712182d3SPeter Maydell 1479712182d3SPeter Maydell if (!vfp_access_check(s)) { 1480712182d3SPeter Maydell return true; 1481712182d3SPeter Maydell } 1482712182d3SPeter Maydell 1483712182d3SPeter Maydell /* 1484712182d3SPeter Maydell * This is always a right shift, and the shiftfn is always a 1485712182d3SPeter Maydell * left-shift helper, which thus needs the negated shift count 1486712182d3SPeter Maydell * duplicated into each lane of the immediate value. 1487712182d3SPeter Maydell */ 1488712182d3SPeter Maydell if (a->size == 1) { 1489712182d3SPeter Maydell imm = (uint16_t)(-a->shift); 1490712182d3SPeter Maydell imm |= imm << 16; 1491712182d3SPeter Maydell } else { 1492712182d3SPeter Maydell /* size == 2 */ 1493712182d3SPeter Maydell imm = -a->shift; 1494712182d3SPeter Maydell } 1495712182d3SPeter Maydell constimm = tcg_const_i32(imm); 1496712182d3SPeter Maydell 1497712182d3SPeter Maydell /* Load all inputs first to avoid potential overwrite */ 1498712182d3SPeter Maydell rm1 = neon_load_reg(a->vm, 0); 1499712182d3SPeter Maydell rm2 = neon_load_reg(a->vm, 1); 1500712182d3SPeter Maydell rm3 = neon_load_reg(a->vm + 1, 0); 1501712182d3SPeter Maydell rm4 = neon_load_reg(a->vm + 1, 1); 1502712182d3SPeter Maydell rtmp = tcg_temp_new_i64(); 1503712182d3SPeter Maydell 1504712182d3SPeter Maydell shiftfn(rm1, rm1, constimm); 1505712182d3SPeter Maydell shiftfn(rm2, rm2, constimm); 1506712182d3SPeter Maydell 1507712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm1, rm2); 1508712182d3SPeter Maydell tcg_temp_free_i32(rm2); 1509712182d3SPeter Maydell 1510712182d3SPeter Maydell narrowfn(rm1, cpu_env, rtmp); 1511712182d3SPeter Maydell neon_store_reg(a->vd, 0, rm1); 1512712182d3SPeter Maydell 1513712182d3SPeter Maydell shiftfn(rm3, rm3, constimm); 1514712182d3SPeter Maydell shiftfn(rm4, rm4, constimm); 1515712182d3SPeter Maydell tcg_temp_free_i32(constimm); 1516712182d3SPeter Maydell 1517712182d3SPeter Maydell tcg_gen_concat_i32_i64(rtmp, rm3, rm4); 1518712182d3SPeter Maydell tcg_temp_free_i32(rm4); 1519712182d3SPeter Maydell 1520712182d3SPeter Maydell narrowfn(rm3, cpu_env, rtmp); 1521712182d3SPeter Maydell tcg_temp_free_i64(rtmp); 1522712182d3SPeter Maydell neon_store_reg(a->vd, 1, rm3); 1523712182d3SPeter Maydell return true; 1524712182d3SPeter Maydell } 1525712182d3SPeter Maydell 1526712182d3SPeter Maydell #define DO_2SN_64(INSN, FUNC, NARROWFUNC) \ 1527712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1528712182d3SPeter Maydell { \ 1529712182d3SPeter Maydell return do_2shift_narrow_64(s, a, FUNC, NARROWFUNC); \ 1530712182d3SPeter Maydell } 1531712182d3SPeter Maydell #define DO_2SN_32(INSN, FUNC, NARROWFUNC) \ 1532712182d3SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 1533712182d3SPeter Maydell { \ 1534712182d3SPeter Maydell return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \ 1535712182d3SPeter Maydell } 1536712182d3SPeter Maydell 1537712182d3SPeter Maydell static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1538712182d3SPeter Maydell { 1539712182d3SPeter Maydell tcg_gen_extrl_i64_i32(dest, src); 1540712182d3SPeter Maydell } 1541712182d3SPeter Maydell 1542712182d3SPeter Maydell static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1543712182d3SPeter Maydell { 1544712182d3SPeter Maydell gen_helper_neon_narrow_u16(dest, src); 1545712182d3SPeter Maydell } 1546712182d3SPeter Maydell 1547712182d3SPeter Maydell static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src) 1548712182d3SPeter Maydell { 1549712182d3SPeter Maydell gen_helper_neon_narrow_u8(dest, src); 1550712182d3SPeter Maydell } 1551712182d3SPeter Maydell 1552712182d3SPeter Maydell DO_2SN_64(VSHRN_64, gen_ushl_i64, gen_neon_narrow_u32) 1553712182d3SPeter Maydell DO_2SN_32(VSHRN_32, gen_ushl_i32, gen_neon_narrow_u16) 1554712182d3SPeter Maydell DO_2SN_32(VSHRN_16, gen_helper_neon_shl_u16, gen_neon_narrow_u8) 1555712182d3SPeter Maydell 1556712182d3SPeter Maydell DO_2SN_64(VRSHRN_64, gen_helper_neon_rshl_u64, gen_neon_narrow_u32) 1557712182d3SPeter Maydell DO_2SN_32(VRSHRN_32, gen_helper_neon_rshl_u32, gen_neon_narrow_u16) 1558712182d3SPeter Maydell DO_2SN_32(VRSHRN_16, gen_helper_neon_rshl_u16, gen_neon_narrow_u8) 1559712182d3SPeter Maydell 1560712182d3SPeter Maydell DO_2SN_64(VQSHRUN_64, gen_sshl_i64, gen_helper_neon_unarrow_sat32) 1561712182d3SPeter Maydell DO_2SN_32(VQSHRUN_32, gen_sshl_i32, gen_helper_neon_unarrow_sat16) 1562712182d3SPeter Maydell DO_2SN_32(VQSHRUN_16, gen_helper_neon_shl_s16, gen_helper_neon_unarrow_sat8) 1563712182d3SPeter Maydell 1564712182d3SPeter Maydell DO_2SN_64(VQRSHRUN_64, gen_helper_neon_rshl_s64, gen_helper_neon_unarrow_sat32) 1565712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_32, gen_helper_neon_rshl_s32, gen_helper_neon_unarrow_sat16) 1566712182d3SPeter Maydell DO_2SN_32(VQRSHRUN_16, gen_helper_neon_rshl_s16, gen_helper_neon_unarrow_sat8) 1567b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_S64, gen_sshl_i64, gen_helper_neon_narrow_sat_s32) 1568b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S32, gen_sshl_i32, gen_helper_neon_narrow_sat_s16) 1569b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_S16, gen_helper_neon_shl_s16, gen_helper_neon_narrow_sat_s8) 1570b4a3a77bSPeter Maydell 1571b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_S64, gen_helper_neon_rshl_s64, gen_helper_neon_narrow_sat_s32) 1572b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S32, gen_helper_neon_rshl_s32, gen_helper_neon_narrow_sat_s16) 1573b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_S16, gen_helper_neon_rshl_s16, gen_helper_neon_narrow_sat_s8) 1574b4a3a77bSPeter Maydell 1575b4a3a77bSPeter Maydell DO_2SN_64(VQSHRN_U64, gen_ushl_i64, gen_helper_neon_narrow_sat_u32) 1576b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U32, gen_ushl_i32, gen_helper_neon_narrow_sat_u16) 1577b4a3a77bSPeter Maydell DO_2SN_32(VQSHRN_U16, gen_helper_neon_shl_u16, gen_helper_neon_narrow_sat_u8) 1578b4a3a77bSPeter Maydell 1579b4a3a77bSPeter Maydell DO_2SN_64(VQRSHRN_U64, gen_helper_neon_rshl_u64, gen_helper_neon_narrow_sat_u32) 1580b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U32, gen_helper_neon_rshl_u32, gen_helper_neon_narrow_sat_u16) 1581b4a3a77bSPeter Maydell DO_2SN_32(VQRSHRN_U16, gen_helper_neon_rshl_u16, gen_helper_neon_narrow_sat_u8) 1582968bf842SPeter Maydell 1583968bf842SPeter Maydell static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, 1584968bf842SPeter Maydell NeonGenWidenFn *widenfn, bool u) 1585968bf842SPeter Maydell { 1586968bf842SPeter Maydell TCGv_i64 tmp; 1587968bf842SPeter Maydell TCGv_i32 rm0, rm1; 1588968bf842SPeter Maydell uint64_t widen_mask = 0; 1589968bf842SPeter Maydell 1590968bf842SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1591968bf842SPeter Maydell return false; 1592968bf842SPeter Maydell } 1593968bf842SPeter Maydell 1594968bf842SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1595968bf842SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1596968bf842SPeter Maydell ((a->vd | a->vm) & 0x10)) { 1597968bf842SPeter Maydell return false; 1598968bf842SPeter Maydell } 1599968bf842SPeter Maydell 1600968bf842SPeter Maydell if (a->vd & 1) { 1601968bf842SPeter Maydell return false; 1602968bf842SPeter Maydell } 1603968bf842SPeter Maydell 1604968bf842SPeter Maydell if (!vfp_access_check(s)) { 1605968bf842SPeter Maydell return true; 1606968bf842SPeter Maydell } 1607968bf842SPeter Maydell 1608968bf842SPeter Maydell /* 1609968bf842SPeter Maydell * This is a widen-and-shift operation. The shift is always less 1610968bf842SPeter Maydell * than the width of the source type, so after widening the input 1611968bf842SPeter Maydell * vector we can simply shift the whole 64-bit widened register, 1612968bf842SPeter Maydell * and then clear the potential overflow bits resulting from left 1613968bf842SPeter Maydell * bits of the narrow input appearing as right bits of the left 1614968bf842SPeter Maydell * neighbour narrow input. Calculate a mask of bits to clear. 1615968bf842SPeter Maydell */ 1616968bf842SPeter Maydell if ((a->shift != 0) && (a->size < 2 || u)) { 1617968bf842SPeter Maydell int esize = 8 << a->size; 1618968bf842SPeter Maydell widen_mask = MAKE_64BIT_MASK(0, esize); 1619968bf842SPeter Maydell widen_mask >>= esize - a->shift; 1620968bf842SPeter Maydell widen_mask = dup_const(a->size + 1, widen_mask); 1621968bf842SPeter Maydell } 1622968bf842SPeter Maydell 1623968bf842SPeter Maydell rm0 = neon_load_reg(a->vm, 0); 1624968bf842SPeter Maydell rm1 = neon_load_reg(a->vm, 1); 1625968bf842SPeter Maydell tmp = tcg_temp_new_i64(); 1626968bf842SPeter Maydell 1627968bf842SPeter Maydell widenfn(tmp, rm0); 16289593a398SPeter Maydell tcg_temp_free_i32(rm0); 1629968bf842SPeter Maydell if (a->shift != 0) { 1630968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1631968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1632968bf842SPeter Maydell } 1633968bf842SPeter Maydell neon_store_reg64(tmp, a->vd); 1634968bf842SPeter Maydell 1635968bf842SPeter Maydell widenfn(tmp, rm1); 16369593a398SPeter Maydell tcg_temp_free_i32(rm1); 1637968bf842SPeter Maydell if (a->shift != 0) { 1638968bf842SPeter Maydell tcg_gen_shli_i64(tmp, tmp, a->shift); 1639968bf842SPeter Maydell tcg_gen_andi_i64(tmp, tmp, ~widen_mask); 1640968bf842SPeter Maydell } 1641968bf842SPeter Maydell neon_store_reg64(tmp, a->vd + 1); 1642968bf842SPeter Maydell tcg_temp_free_i64(tmp); 1643968bf842SPeter Maydell return true; 1644968bf842SPeter Maydell } 1645968bf842SPeter Maydell 1646968bf842SPeter Maydell static bool trans_VSHLL_S_2sh(DisasContext *s, arg_2reg_shift *a) 1647968bf842SPeter Maydell { 1648448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1649968bf842SPeter Maydell gen_helper_neon_widen_s8, 1650968bf842SPeter Maydell gen_helper_neon_widen_s16, 1651968bf842SPeter Maydell tcg_gen_ext_i32_i64, 1652968bf842SPeter Maydell }; 1653968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], false); 1654968bf842SPeter Maydell } 1655968bf842SPeter Maydell 1656968bf842SPeter Maydell static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) 1657968bf842SPeter Maydell { 1658448f0e5fSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 1659968bf842SPeter Maydell gen_helper_neon_widen_u8, 1660968bf842SPeter Maydell gen_helper_neon_widen_u16, 1661968bf842SPeter Maydell tcg_gen_extu_i32_i64, 1662968bf842SPeter Maydell }; 1663968bf842SPeter Maydell return do_vshll_2sh(s, a, widenfn[a->size], true); 1664968bf842SPeter Maydell } 16653da26f11SPeter Maydell 16663da26f11SPeter Maydell static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, 16675de3fd04SPeter Maydell NeonGenTwoSingleOpFn *fn) 16683da26f11SPeter Maydell { 16693da26f11SPeter Maydell /* FP operations in 2-reg-and-shift group */ 16703da26f11SPeter Maydell TCGv_i32 tmp, shiftv; 16713da26f11SPeter Maydell TCGv_ptr fpstatus; 16723da26f11SPeter Maydell int pass; 16733da26f11SPeter Maydell 16743da26f11SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 16753da26f11SPeter Maydell return false; 16763da26f11SPeter Maydell } 16773da26f11SPeter Maydell 16783da26f11SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 16793da26f11SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 16803da26f11SPeter Maydell ((a->vd | a->vm) & 0x10)) { 16813da26f11SPeter Maydell return false; 16823da26f11SPeter Maydell } 16833da26f11SPeter Maydell 16843da26f11SPeter Maydell if ((a->vm | a->vd) & a->q) { 16853da26f11SPeter Maydell return false; 16863da26f11SPeter Maydell } 16873da26f11SPeter Maydell 16883da26f11SPeter Maydell if (!vfp_access_check(s)) { 16893da26f11SPeter Maydell return true; 16903da26f11SPeter Maydell } 16913da26f11SPeter Maydell 16923da26f11SPeter Maydell fpstatus = get_fpstatus_ptr(1); 16933da26f11SPeter Maydell shiftv = tcg_const_i32(a->shift); 16943da26f11SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 16953da26f11SPeter Maydell tmp = neon_load_reg(a->vm, pass); 16963da26f11SPeter Maydell fn(tmp, tmp, shiftv, fpstatus); 16973da26f11SPeter Maydell neon_store_reg(a->vd, pass, tmp); 16983da26f11SPeter Maydell } 16993da26f11SPeter Maydell tcg_temp_free_ptr(fpstatus); 17003da26f11SPeter Maydell tcg_temp_free_i32(shiftv); 17013da26f11SPeter Maydell return true; 17023da26f11SPeter Maydell } 17033da26f11SPeter Maydell 17043da26f11SPeter Maydell #define DO_FP_2SH(INSN, FUNC) \ 17053da26f11SPeter Maydell static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \ 17063da26f11SPeter Maydell { \ 17073da26f11SPeter Maydell return do_fp_2sh(s, a, FUNC); \ 17083da26f11SPeter Maydell } 17093da26f11SPeter Maydell 17103da26f11SPeter Maydell DO_FP_2SH(VCVT_SF, gen_helper_vfp_sltos) 17113da26f11SPeter Maydell DO_FP_2SH(VCVT_UF, gen_helper_vfp_ultos) 17123da26f11SPeter Maydell DO_FP_2SH(VCVT_FS, gen_helper_vfp_tosls_round_to_zero) 17133da26f11SPeter Maydell DO_FP_2SH(VCVT_FU, gen_helper_vfp_touls_round_to_zero) 17142c35a39eSPeter Maydell 17152c35a39eSPeter Maydell static uint64_t asimd_imm_const(uint32_t imm, int cmode, int op) 17162c35a39eSPeter Maydell { 17172c35a39eSPeter Maydell /* 17182c35a39eSPeter Maydell * Expand the encoded constant. 17192c35a39eSPeter Maydell * Note that cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE. 17202c35a39eSPeter Maydell * We choose to not special-case this and will behave as if a 17212c35a39eSPeter Maydell * valid constant encoding of 0 had been given. 17222c35a39eSPeter Maydell * cmode = 15 op = 1 must UNDEF; we assume decode has handled that. 17232c35a39eSPeter Maydell */ 17242c35a39eSPeter Maydell switch (cmode) { 17252c35a39eSPeter Maydell case 0: case 1: 17262c35a39eSPeter Maydell /* no-op */ 17272c35a39eSPeter Maydell break; 17282c35a39eSPeter Maydell case 2: case 3: 17292c35a39eSPeter Maydell imm <<= 8; 17302c35a39eSPeter Maydell break; 17312c35a39eSPeter Maydell case 4: case 5: 17322c35a39eSPeter Maydell imm <<= 16; 17332c35a39eSPeter Maydell break; 17342c35a39eSPeter Maydell case 6: case 7: 17352c35a39eSPeter Maydell imm <<= 24; 17362c35a39eSPeter Maydell break; 17372c35a39eSPeter Maydell case 8: case 9: 17382c35a39eSPeter Maydell imm |= imm << 16; 17392c35a39eSPeter Maydell break; 17402c35a39eSPeter Maydell case 10: case 11: 17412c35a39eSPeter Maydell imm = (imm << 8) | (imm << 24); 17422c35a39eSPeter Maydell break; 17432c35a39eSPeter Maydell case 12: 17442c35a39eSPeter Maydell imm = (imm << 8) | 0xff; 17452c35a39eSPeter Maydell break; 17462c35a39eSPeter Maydell case 13: 17472c35a39eSPeter Maydell imm = (imm << 16) | 0xffff; 17482c35a39eSPeter Maydell break; 17492c35a39eSPeter Maydell case 14: 17502c35a39eSPeter Maydell if (op) { 17512c35a39eSPeter Maydell /* 17522c35a39eSPeter Maydell * This is the only case where the top and bottom 32 bits 17532c35a39eSPeter Maydell * of the encoded constant differ. 17542c35a39eSPeter Maydell */ 17552c35a39eSPeter Maydell uint64_t imm64 = 0; 17562c35a39eSPeter Maydell int n; 17572c35a39eSPeter Maydell 17582c35a39eSPeter Maydell for (n = 0; n < 8; n++) { 17592c35a39eSPeter Maydell if (imm & (1 << n)) { 17602c35a39eSPeter Maydell imm64 |= (0xffULL << (n * 8)); 17612c35a39eSPeter Maydell } 17622c35a39eSPeter Maydell } 17632c35a39eSPeter Maydell return imm64; 17642c35a39eSPeter Maydell } 17652c35a39eSPeter Maydell imm |= (imm << 8) | (imm << 16) | (imm << 24); 17662c35a39eSPeter Maydell break; 17672c35a39eSPeter Maydell case 15: 17682c35a39eSPeter Maydell imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19) 17692c35a39eSPeter Maydell | ((imm & 0x40) ? (0x1f << 25) : (1 << 30)); 17702c35a39eSPeter Maydell break; 17712c35a39eSPeter Maydell } 17722c35a39eSPeter Maydell if (op) { 17732c35a39eSPeter Maydell imm = ~imm; 17742c35a39eSPeter Maydell } 17752c35a39eSPeter Maydell return dup_const(MO_32, imm); 17762c35a39eSPeter Maydell } 17772c35a39eSPeter Maydell 17782c35a39eSPeter Maydell static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, 17792c35a39eSPeter Maydell GVecGen2iFn *fn) 17802c35a39eSPeter Maydell { 17812c35a39eSPeter Maydell uint64_t imm; 17822c35a39eSPeter Maydell int reg_ofs, vec_size; 17832c35a39eSPeter Maydell 17842c35a39eSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 17852c35a39eSPeter Maydell return false; 17862c35a39eSPeter Maydell } 17872c35a39eSPeter Maydell 17882c35a39eSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 17892c35a39eSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { 17902c35a39eSPeter Maydell return false; 17912c35a39eSPeter Maydell } 17922c35a39eSPeter Maydell 17932c35a39eSPeter Maydell if (a->vd & a->q) { 17942c35a39eSPeter Maydell return false; 17952c35a39eSPeter Maydell } 17962c35a39eSPeter Maydell 17972c35a39eSPeter Maydell if (!vfp_access_check(s)) { 17982c35a39eSPeter Maydell return true; 17992c35a39eSPeter Maydell } 18002c35a39eSPeter Maydell 18012c35a39eSPeter Maydell reg_ofs = neon_reg_offset(a->vd, 0); 18022c35a39eSPeter Maydell vec_size = a->q ? 16 : 8; 18032c35a39eSPeter Maydell imm = asimd_imm_const(a->imm, a->cmode, a->op); 18042c35a39eSPeter Maydell 18052c35a39eSPeter Maydell fn(MO_64, reg_ofs, reg_ofs, imm, vec_size, vec_size); 18062c35a39eSPeter Maydell return true; 18072c35a39eSPeter Maydell } 18082c35a39eSPeter Maydell 18092c35a39eSPeter Maydell static void gen_VMOV_1r(unsigned vece, uint32_t dofs, uint32_t aofs, 18102c35a39eSPeter Maydell int64_t c, uint32_t oprsz, uint32_t maxsz) 18112c35a39eSPeter Maydell { 18122c35a39eSPeter Maydell tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c); 18132c35a39eSPeter Maydell } 18142c35a39eSPeter Maydell 18152c35a39eSPeter Maydell static bool trans_Vimm_1r(DisasContext *s, arg_1reg_imm *a) 18162c35a39eSPeter Maydell { 18172c35a39eSPeter Maydell /* Handle decode of cmode/op here between VORR/VBIC/VMOV */ 18182c35a39eSPeter Maydell GVecGen2iFn *fn; 18192c35a39eSPeter Maydell 18202c35a39eSPeter Maydell if ((a->cmode & 1) && a->cmode < 12) { 18212c35a39eSPeter Maydell /* for op=1, the imm will be inverted, so BIC becomes AND. */ 18222c35a39eSPeter Maydell fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori; 18232c35a39eSPeter Maydell } else { 18242c35a39eSPeter Maydell /* There is one unallocated cmode/op combination in this space */ 18252c35a39eSPeter Maydell if (a->cmode == 15 && a->op == 1) { 18262c35a39eSPeter Maydell return false; 18272c35a39eSPeter Maydell } 18282c35a39eSPeter Maydell fn = gen_VMOV_1r; 18292c35a39eSPeter Maydell } 18302c35a39eSPeter Maydell return do_1reg_imm(s, a, fn); 18312c35a39eSPeter Maydell } 1832b28be095SPeter Maydell 1833b28be095SPeter Maydell static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, 1834b28be095SPeter Maydell NeonGenWidenFn *widenfn, 1835b28be095SPeter Maydell NeonGenTwo64OpFn *opfn, 1836b28be095SPeter Maydell bool src1_wide) 1837b28be095SPeter Maydell { 1838b28be095SPeter Maydell /* 3-regs different lengths, prewidening case (VADDL/VSUBL/VAADW/VSUBW) */ 1839b28be095SPeter Maydell TCGv_i64 rn0_64, rn1_64, rm_64; 1840b28be095SPeter Maydell TCGv_i32 rm; 1841b28be095SPeter Maydell 1842b28be095SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 1843b28be095SPeter Maydell return false; 1844b28be095SPeter Maydell } 1845b28be095SPeter Maydell 1846b28be095SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 1847b28be095SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 1848b28be095SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 1849b28be095SPeter Maydell return false; 1850b28be095SPeter Maydell } 1851b28be095SPeter Maydell 1852b28be095SPeter Maydell if (!widenfn || !opfn) { 1853b28be095SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 1854b28be095SPeter Maydell return false; 1855b28be095SPeter Maydell } 1856b28be095SPeter Maydell 1857b28be095SPeter Maydell if ((a->vd & 1) || (src1_wide && (a->vn & 1))) { 1858b28be095SPeter Maydell return false; 1859b28be095SPeter Maydell } 1860b28be095SPeter Maydell 1861b28be095SPeter Maydell if (!vfp_access_check(s)) { 1862b28be095SPeter Maydell return true; 1863b28be095SPeter Maydell } 1864b28be095SPeter Maydell 1865b28be095SPeter Maydell rn0_64 = tcg_temp_new_i64(); 1866b28be095SPeter Maydell rn1_64 = tcg_temp_new_i64(); 1867b28be095SPeter Maydell rm_64 = tcg_temp_new_i64(); 1868b28be095SPeter Maydell 1869b28be095SPeter Maydell if (src1_wide) { 1870b28be095SPeter Maydell neon_load_reg64(rn0_64, a->vn); 1871b28be095SPeter Maydell } else { 1872b28be095SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, 0); 1873b28be095SPeter Maydell widenfn(rn0_64, tmp); 1874b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1875b28be095SPeter Maydell } 1876b28be095SPeter Maydell rm = neon_load_reg(a->vm, 0); 1877b28be095SPeter Maydell 1878b28be095SPeter Maydell widenfn(rm_64, rm); 1879b28be095SPeter Maydell tcg_temp_free_i32(rm); 1880b28be095SPeter Maydell opfn(rn0_64, rn0_64, rm_64); 1881b28be095SPeter Maydell 1882b28be095SPeter Maydell /* 1883b28be095SPeter Maydell * Load second pass inputs before storing the first pass result, to 1884b28be095SPeter Maydell * avoid incorrect results if a narrow input overlaps with the result. 1885b28be095SPeter Maydell */ 1886b28be095SPeter Maydell if (src1_wide) { 1887b28be095SPeter Maydell neon_load_reg64(rn1_64, a->vn + 1); 1888b28be095SPeter Maydell } else { 1889b28be095SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, 1); 1890b28be095SPeter Maydell widenfn(rn1_64, tmp); 1891b28be095SPeter Maydell tcg_temp_free_i32(tmp); 1892b28be095SPeter Maydell } 1893b28be095SPeter Maydell rm = neon_load_reg(a->vm, 1); 1894b28be095SPeter Maydell 1895b28be095SPeter Maydell neon_store_reg64(rn0_64, a->vd); 1896b28be095SPeter Maydell 1897b28be095SPeter Maydell widenfn(rm_64, rm); 1898b28be095SPeter Maydell tcg_temp_free_i32(rm); 1899b28be095SPeter Maydell opfn(rn1_64, rn1_64, rm_64); 1900b28be095SPeter Maydell neon_store_reg64(rn1_64, a->vd + 1); 1901b28be095SPeter Maydell 1902b28be095SPeter Maydell tcg_temp_free_i64(rn0_64); 1903b28be095SPeter Maydell tcg_temp_free_i64(rn1_64); 1904b28be095SPeter Maydell tcg_temp_free_i64(rm_64); 1905b28be095SPeter Maydell 1906b28be095SPeter Maydell return true; 1907b28be095SPeter Maydell } 1908b28be095SPeter Maydell 1909b28be095SPeter Maydell #define DO_PREWIDEN(INSN, S, EXT, OP, SRC1WIDE) \ 1910b28be095SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 1911b28be095SPeter Maydell { \ 1912b28be095SPeter Maydell static NeonGenWidenFn * const widenfn[] = { \ 1913b28be095SPeter Maydell gen_helper_neon_widen_##S##8, \ 1914b28be095SPeter Maydell gen_helper_neon_widen_##S##16, \ 1915b28be095SPeter Maydell tcg_gen_##EXT##_i32_i64, \ 1916b28be095SPeter Maydell NULL, \ 1917b28be095SPeter Maydell }; \ 1918b28be095SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 1919b28be095SPeter Maydell gen_helper_neon_##OP##l_u16, \ 1920b28be095SPeter Maydell gen_helper_neon_##OP##l_u32, \ 1921b28be095SPeter Maydell tcg_gen_##OP##_i64, \ 1922b28be095SPeter Maydell NULL, \ 1923b28be095SPeter Maydell }; \ 1924b28be095SPeter Maydell return do_prewiden_3d(s, a, widenfn[a->size], \ 1925b28be095SPeter Maydell addfn[a->size], SRC1WIDE); \ 1926b28be095SPeter Maydell } 1927b28be095SPeter Maydell 1928b28be095SPeter Maydell DO_PREWIDEN(VADDL_S, s, ext, add, false) 1929b28be095SPeter Maydell DO_PREWIDEN(VADDL_U, u, extu, add, false) 1930b28be095SPeter Maydell DO_PREWIDEN(VSUBL_S, s, ext, sub, false) 1931b28be095SPeter Maydell DO_PREWIDEN(VSUBL_U, u, extu, sub, false) 1932b28be095SPeter Maydell DO_PREWIDEN(VADDW_S, s, ext, add, true) 1933b28be095SPeter Maydell DO_PREWIDEN(VADDW_U, u, extu, add, true) 1934b28be095SPeter Maydell DO_PREWIDEN(VSUBW_S, s, ext, sub, true) 1935b28be095SPeter Maydell DO_PREWIDEN(VSUBW_U, u, extu, sub, true) 19360fa1ab03SPeter Maydell 19370fa1ab03SPeter Maydell static bool do_narrow_3d(DisasContext *s, arg_3diff *a, 19380fa1ab03SPeter Maydell NeonGenTwo64OpFn *opfn, NeonGenNarrowFn *narrowfn) 19390fa1ab03SPeter Maydell { 19400fa1ab03SPeter Maydell /* 3-regs different lengths, narrowing (VADDHN/VSUBHN/VRADDHN/VRSUBHN) */ 19410fa1ab03SPeter Maydell TCGv_i64 rn_64, rm_64; 19420fa1ab03SPeter Maydell TCGv_i32 rd0, rd1; 19430fa1ab03SPeter Maydell 19440fa1ab03SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 19450fa1ab03SPeter Maydell return false; 19460fa1ab03SPeter Maydell } 19470fa1ab03SPeter Maydell 19480fa1ab03SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 19490fa1ab03SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 19500fa1ab03SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 19510fa1ab03SPeter Maydell return false; 19520fa1ab03SPeter Maydell } 19530fa1ab03SPeter Maydell 19540fa1ab03SPeter Maydell if (!opfn || !narrowfn) { 19550fa1ab03SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 19560fa1ab03SPeter Maydell return false; 19570fa1ab03SPeter Maydell } 19580fa1ab03SPeter Maydell 19590fa1ab03SPeter Maydell if ((a->vn | a->vm) & 1) { 19600fa1ab03SPeter Maydell return false; 19610fa1ab03SPeter Maydell } 19620fa1ab03SPeter Maydell 19630fa1ab03SPeter Maydell if (!vfp_access_check(s)) { 19640fa1ab03SPeter Maydell return true; 19650fa1ab03SPeter Maydell } 19660fa1ab03SPeter Maydell 19670fa1ab03SPeter Maydell rn_64 = tcg_temp_new_i64(); 19680fa1ab03SPeter Maydell rm_64 = tcg_temp_new_i64(); 19690fa1ab03SPeter Maydell rd0 = tcg_temp_new_i32(); 19700fa1ab03SPeter Maydell rd1 = tcg_temp_new_i32(); 19710fa1ab03SPeter Maydell 19720fa1ab03SPeter Maydell neon_load_reg64(rn_64, a->vn); 19730fa1ab03SPeter Maydell neon_load_reg64(rm_64, a->vm); 19740fa1ab03SPeter Maydell 19750fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19760fa1ab03SPeter Maydell 19770fa1ab03SPeter Maydell narrowfn(rd0, rn_64); 19780fa1ab03SPeter Maydell 19790fa1ab03SPeter Maydell neon_load_reg64(rn_64, a->vn + 1); 19800fa1ab03SPeter Maydell neon_load_reg64(rm_64, a->vm + 1); 19810fa1ab03SPeter Maydell 19820fa1ab03SPeter Maydell opfn(rn_64, rn_64, rm_64); 19830fa1ab03SPeter Maydell 19840fa1ab03SPeter Maydell narrowfn(rd1, rn_64); 19850fa1ab03SPeter Maydell 19860fa1ab03SPeter Maydell neon_store_reg(a->vd, 0, rd0); 19870fa1ab03SPeter Maydell neon_store_reg(a->vd, 1, rd1); 19880fa1ab03SPeter Maydell 19890fa1ab03SPeter Maydell tcg_temp_free_i64(rn_64); 19900fa1ab03SPeter Maydell tcg_temp_free_i64(rm_64); 19910fa1ab03SPeter Maydell 19920fa1ab03SPeter Maydell return true; 19930fa1ab03SPeter Maydell } 19940fa1ab03SPeter Maydell 19950fa1ab03SPeter Maydell #define DO_NARROW_3D(INSN, OP, NARROWTYPE, EXTOP) \ 19960fa1ab03SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 19970fa1ab03SPeter Maydell { \ 19980fa1ab03SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { \ 19990fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u16, \ 20000fa1ab03SPeter Maydell gen_helper_neon_##OP##l_u32, \ 20010fa1ab03SPeter Maydell tcg_gen_##OP##_i64, \ 20020fa1ab03SPeter Maydell NULL, \ 20030fa1ab03SPeter Maydell }; \ 20040fa1ab03SPeter Maydell static NeonGenNarrowFn * const narrowfn[] = { \ 20050fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u8, \ 20060fa1ab03SPeter Maydell gen_helper_neon_##NARROWTYPE##_high_u16, \ 20070fa1ab03SPeter Maydell EXTOP, \ 20080fa1ab03SPeter Maydell NULL, \ 20090fa1ab03SPeter Maydell }; \ 20100fa1ab03SPeter Maydell return do_narrow_3d(s, a, addfn[a->size], narrowfn[a->size]); \ 20110fa1ab03SPeter Maydell } 20120fa1ab03SPeter Maydell 20130fa1ab03SPeter Maydell static void gen_narrow_round_high_u32(TCGv_i32 rd, TCGv_i64 rn) 20140fa1ab03SPeter Maydell { 20150fa1ab03SPeter Maydell tcg_gen_addi_i64(rn, rn, 1u << 31); 20160fa1ab03SPeter Maydell tcg_gen_extrh_i64_i32(rd, rn); 20170fa1ab03SPeter Maydell } 20180fa1ab03SPeter Maydell 20190fa1ab03SPeter Maydell DO_NARROW_3D(VADDHN, add, narrow, tcg_gen_extrh_i64_i32) 20200fa1ab03SPeter Maydell DO_NARROW_3D(VSUBHN, sub, narrow, tcg_gen_extrh_i64_i32) 20210fa1ab03SPeter Maydell DO_NARROW_3D(VRADDHN, add, narrow_round, gen_narrow_round_high_u32) 20220fa1ab03SPeter Maydell DO_NARROW_3D(VRSUBHN, sub, narrow_round, gen_narrow_round_high_u32) 2023f5b28401SPeter Maydell 2024f5b28401SPeter Maydell static bool do_long_3d(DisasContext *s, arg_3diff *a, 2025f5b28401SPeter Maydell NeonGenTwoOpWidenFn *opfn, 2026f5b28401SPeter Maydell NeonGenTwo64OpFn *accfn) 2027f5b28401SPeter Maydell { 2028f5b28401SPeter Maydell /* 2029f5b28401SPeter Maydell * 3-regs different lengths, long operations. 2030f5b28401SPeter Maydell * These perform an operation on two inputs that returns a double-width 2031f5b28401SPeter Maydell * result, and then possibly perform an accumulation operation of 2032f5b28401SPeter Maydell * that result into the double-width destination. 2033f5b28401SPeter Maydell */ 2034f5b28401SPeter Maydell TCGv_i64 rd0, rd1, tmp; 2035f5b28401SPeter Maydell TCGv_i32 rn, rm; 2036f5b28401SPeter Maydell 2037f5b28401SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2038f5b28401SPeter Maydell return false; 2039f5b28401SPeter Maydell } 2040f5b28401SPeter Maydell 2041f5b28401SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2042f5b28401SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2043f5b28401SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2044f5b28401SPeter Maydell return false; 2045f5b28401SPeter Maydell } 2046f5b28401SPeter Maydell 2047f5b28401SPeter Maydell if (!opfn) { 2048f5b28401SPeter Maydell /* size == 3 case, which is an entirely different insn group */ 2049f5b28401SPeter Maydell return false; 2050f5b28401SPeter Maydell } 2051f5b28401SPeter Maydell 2052f5b28401SPeter Maydell if (a->vd & 1) { 2053f5b28401SPeter Maydell return false; 2054f5b28401SPeter Maydell } 2055f5b28401SPeter Maydell 2056f5b28401SPeter Maydell if (!vfp_access_check(s)) { 2057f5b28401SPeter Maydell return true; 2058f5b28401SPeter Maydell } 2059f5b28401SPeter Maydell 2060f5b28401SPeter Maydell rd0 = tcg_temp_new_i64(); 2061f5b28401SPeter Maydell rd1 = tcg_temp_new_i64(); 2062f5b28401SPeter Maydell 2063f5b28401SPeter Maydell rn = neon_load_reg(a->vn, 0); 2064f5b28401SPeter Maydell rm = neon_load_reg(a->vm, 0); 2065f5b28401SPeter Maydell opfn(rd0, rn, rm); 2066f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2067f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2068f5b28401SPeter Maydell 2069f5b28401SPeter Maydell rn = neon_load_reg(a->vn, 1); 2070f5b28401SPeter Maydell rm = neon_load_reg(a->vm, 1); 2071f5b28401SPeter Maydell opfn(rd1, rn, rm); 2072f5b28401SPeter Maydell tcg_temp_free_i32(rn); 2073f5b28401SPeter Maydell tcg_temp_free_i32(rm); 2074f5b28401SPeter Maydell 2075f5b28401SPeter Maydell /* Don't store results until after all loads: they might overlap */ 2076f5b28401SPeter Maydell if (accfn) { 2077f5b28401SPeter Maydell tmp = tcg_temp_new_i64(); 2078f5b28401SPeter Maydell neon_load_reg64(tmp, a->vd); 2079f5b28401SPeter Maydell accfn(tmp, tmp, rd0); 2080f5b28401SPeter Maydell neon_store_reg64(tmp, a->vd); 2081f5b28401SPeter Maydell neon_load_reg64(tmp, a->vd + 1); 2082f5b28401SPeter Maydell accfn(tmp, tmp, rd1); 2083f5b28401SPeter Maydell neon_store_reg64(tmp, a->vd + 1); 2084f5b28401SPeter Maydell tcg_temp_free_i64(tmp); 2085f5b28401SPeter Maydell } else { 2086f5b28401SPeter Maydell neon_store_reg64(rd0, a->vd); 2087f5b28401SPeter Maydell neon_store_reg64(rd1, a->vd + 1); 2088f5b28401SPeter Maydell } 2089f5b28401SPeter Maydell 2090f5b28401SPeter Maydell tcg_temp_free_i64(rd0); 2091f5b28401SPeter Maydell tcg_temp_free_i64(rd1); 2092f5b28401SPeter Maydell 2093f5b28401SPeter Maydell return true; 2094f5b28401SPeter Maydell } 2095f5b28401SPeter Maydell 2096f5b28401SPeter Maydell static bool trans_VABDL_S_3d(DisasContext *s, arg_3diff *a) 2097f5b28401SPeter Maydell { 2098f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2099f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2100f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2101f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2102f5b28401SPeter Maydell NULL, 2103f5b28401SPeter Maydell }; 2104f5b28401SPeter Maydell 2105f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2106f5b28401SPeter Maydell } 2107f5b28401SPeter Maydell 2108f5b28401SPeter Maydell static bool trans_VABDL_U_3d(DisasContext *s, arg_3diff *a) 2109f5b28401SPeter Maydell { 2110f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2111f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2112f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2113f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2114f5b28401SPeter Maydell NULL, 2115f5b28401SPeter Maydell }; 2116f5b28401SPeter Maydell 2117f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 2118f5b28401SPeter Maydell } 2119f5b28401SPeter Maydell 2120f5b28401SPeter Maydell static bool trans_VABAL_S_3d(DisasContext *s, arg_3diff *a) 2121f5b28401SPeter Maydell { 2122f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2123f5b28401SPeter Maydell gen_helper_neon_abdl_s16, 2124f5b28401SPeter Maydell gen_helper_neon_abdl_s32, 2125f5b28401SPeter Maydell gen_helper_neon_abdl_s64, 2126f5b28401SPeter Maydell NULL, 2127f5b28401SPeter Maydell }; 2128f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2129f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2130f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2131f5b28401SPeter Maydell tcg_gen_add_i64, 2132f5b28401SPeter Maydell NULL, 2133f5b28401SPeter Maydell }; 2134f5b28401SPeter Maydell 2135f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2136f5b28401SPeter Maydell } 2137f5b28401SPeter Maydell 2138f5b28401SPeter Maydell static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) 2139f5b28401SPeter Maydell { 2140f5b28401SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 2141f5b28401SPeter Maydell gen_helper_neon_abdl_u16, 2142f5b28401SPeter Maydell gen_helper_neon_abdl_u32, 2143f5b28401SPeter Maydell gen_helper_neon_abdl_u64, 2144f5b28401SPeter Maydell NULL, 2145f5b28401SPeter Maydell }; 2146f5b28401SPeter Maydell static NeonGenTwo64OpFn * const addfn[] = { 2147f5b28401SPeter Maydell gen_helper_neon_addl_u16, 2148f5b28401SPeter Maydell gen_helper_neon_addl_u32, 2149f5b28401SPeter Maydell tcg_gen_add_i64, 2150f5b28401SPeter Maydell NULL, 2151f5b28401SPeter Maydell }; 2152f5b28401SPeter Maydell 2153f5b28401SPeter Maydell return do_long_3d(s, a, opfn[a->size], addfn[a->size]); 2154f5b28401SPeter Maydell } 21553a1d9eb0SPeter Maydell 21563a1d9eb0SPeter Maydell static void gen_mull_s32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21573a1d9eb0SPeter Maydell { 21583a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21593a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21603a1d9eb0SPeter Maydell 21613a1d9eb0SPeter Maydell tcg_gen_muls2_i32(lo, hi, rn, rm); 21623a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21633a1d9eb0SPeter Maydell 21643a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21653a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21663a1d9eb0SPeter Maydell } 21673a1d9eb0SPeter Maydell 21683a1d9eb0SPeter Maydell static void gen_mull_u32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 21693a1d9eb0SPeter Maydell { 21703a1d9eb0SPeter Maydell TCGv_i32 lo = tcg_temp_new_i32(); 21713a1d9eb0SPeter Maydell TCGv_i32 hi = tcg_temp_new_i32(); 21723a1d9eb0SPeter Maydell 21733a1d9eb0SPeter Maydell tcg_gen_mulu2_i32(lo, hi, rn, rm); 21743a1d9eb0SPeter Maydell tcg_gen_concat_i32_i64(rd, lo, hi); 21753a1d9eb0SPeter Maydell 21763a1d9eb0SPeter Maydell tcg_temp_free_i32(lo); 21773a1d9eb0SPeter Maydell tcg_temp_free_i32(hi); 21783a1d9eb0SPeter Maydell } 21793a1d9eb0SPeter Maydell 21803a1d9eb0SPeter Maydell static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) 21813a1d9eb0SPeter Maydell { 21823a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21833a1d9eb0SPeter Maydell gen_helper_neon_mull_s8, 21843a1d9eb0SPeter Maydell gen_helper_neon_mull_s16, 21853a1d9eb0SPeter Maydell gen_mull_s32, 21863a1d9eb0SPeter Maydell NULL, 21873a1d9eb0SPeter Maydell }; 21883a1d9eb0SPeter Maydell 21893a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 21903a1d9eb0SPeter Maydell } 21913a1d9eb0SPeter Maydell 21923a1d9eb0SPeter Maydell static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) 21933a1d9eb0SPeter Maydell { 21943a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 21953a1d9eb0SPeter Maydell gen_helper_neon_mull_u8, 21963a1d9eb0SPeter Maydell gen_helper_neon_mull_u16, 21973a1d9eb0SPeter Maydell gen_mull_u32, 21983a1d9eb0SPeter Maydell NULL, 21993a1d9eb0SPeter Maydell }; 22003a1d9eb0SPeter Maydell 22013a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22023a1d9eb0SPeter Maydell } 22033a1d9eb0SPeter Maydell 22043a1d9eb0SPeter Maydell #define DO_VMLAL(INSN,MULL,ACC) \ 22053a1d9eb0SPeter Maydell static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ 22063a1d9eb0SPeter Maydell { \ 22073a1d9eb0SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 22083a1d9eb0SPeter Maydell gen_helper_neon_##MULL##8, \ 22093a1d9eb0SPeter Maydell gen_helper_neon_##MULL##16, \ 22103a1d9eb0SPeter Maydell gen_##MULL##32, \ 22113a1d9eb0SPeter Maydell NULL, \ 22123a1d9eb0SPeter Maydell }; \ 22133a1d9eb0SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 22143a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u16, \ 22153a1d9eb0SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 22163a1d9eb0SPeter Maydell tcg_gen_##ACC##_i64, \ 22173a1d9eb0SPeter Maydell NULL, \ 22183a1d9eb0SPeter Maydell }; \ 22193a1d9eb0SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ 22203a1d9eb0SPeter Maydell } 22213a1d9eb0SPeter Maydell 22223a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_S,mull_s,add) 22233a1d9eb0SPeter Maydell DO_VMLAL(VMLAL_U,mull_u,add) 22243a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_S,mull_s,sub) 22253a1d9eb0SPeter Maydell DO_VMLAL(VMLSL_U,mull_u,sub) 22269546ca59SPeter Maydell 22279546ca59SPeter Maydell static void gen_VQDMULL_16(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22289546ca59SPeter Maydell { 22299546ca59SPeter Maydell gen_helper_neon_mull_s16(rd, rn, rm); 22309546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rd, rd); 22319546ca59SPeter Maydell } 22329546ca59SPeter Maydell 22339546ca59SPeter Maydell static void gen_VQDMULL_32(TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) 22349546ca59SPeter Maydell { 22359546ca59SPeter Maydell gen_mull_s32(rd, rn, rm); 22369546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rd, rd); 22379546ca59SPeter Maydell } 22389546ca59SPeter Maydell 22399546ca59SPeter Maydell static bool trans_VQDMULL_3d(DisasContext *s, arg_3diff *a) 22409546ca59SPeter Maydell { 22419546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22429546ca59SPeter Maydell NULL, 22439546ca59SPeter Maydell gen_VQDMULL_16, 22449546ca59SPeter Maydell gen_VQDMULL_32, 22459546ca59SPeter Maydell NULL, 22469546ca59SPeter Maydell }; 22479546ca59SPeter Maydell 22489546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], NULL); 22499546ca59SPeter Maydell } 22509546ca59SPeter Maydell 22519546ca59SPeter Maydell static void gen_VQDMLAL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22529546ca59SPeter Maydell { 22539546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22549546ca59SPeter Maydell } 22559546ca59SPeter Maydell 22569546ca59SPeter Maydell static void gen_VQDMLAL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22579546ca59SPeter Maydell { 22589546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22599546ca59SPeter Maydell } 22609546ca59SPeter Maydell 22619546ca59SPeter Maydell static bool trans_VQDMLAL_3d(DisasContext *s, arg_3diff *a) 22629546ca59SPeter Maydell { 22639546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22649546ca59SPeter Maydell NULL, 22659546ca59SPeter Maydell gen_VQDMULL_16, 22669546ca59SPeter Maydell gen_VQDMULL_32, 22679546ca59SPeter Maydell NULL, 22689546ca59SPeter Maydell }; 22699546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 22709546ca59SPeter Maydell NULL, 22719546ca59SPeter Maydell gen_VQDMLAL_acc_16, 22729546ca59SPeter Maydell gen_VQDMLAL_acc_32, 22739546ca59SPeter Maydell NULL, 22749546ca59SPeter Maydell }; 22759546ca59SPeter Maydell 22769546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 22779546ca59SPeter Maydell } 22789546ca59SPeter Maydell 22799546ca59SPeter Maydell static void gen_VQDMLSL_acc_16(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22809546ca59SPeter Maydell { 22819546ca59SPeter Maydell gen_helper_neon_negl_u32(rm, rm); 22829546ca59SPeter Maydell gen_helper_neon_addl_saturate_s32(rd, cpu_env, rn, rm); 22839546ca59SPeter Maydell } 22849546ca59SPeter Maydell 22859546ca59SPeter Maydell static void gen_VQDMLSL_acc_32(TCGv_i64 rd, TCGv_i64 rn, TCGv_i64 rm) 22869546ca59SPeter Maydell { 22879546ca59SPeter Maydell tcg_gen_neg_i64(rm, rm); 22889546ca59SPeter Maydell gen_helper_neon_addl_saturate_s64(rd, cpu_env, rn, rm); 22899546ca59SPeter Maydell } 22909546ca59SPeter Maydell 22919546ca59SPeter Maydell static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a) 22929546ca59SPeter Maydell { 22939546ca59SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 22949546ca59SPeter Maydell NULL, 22959546ca59SPeter Maydell gen_VQDMULL_16, 22969546ca59SPeter Maydell gen_VQDMULL_32, 22979546ca59SPeter Maydell NULL, 22989546ca59SPeter Maydell }; 22999546ca59SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 23009546ca59SPeter Maydell NULL, 23019546ca59SPeter Maydell gen_VQDMLSL_acc_16, 23029546ca59SPeter Maydell gen_VQDMLSL_acc_32, 23039546ca59SPeter Maydell NULL, 23049546ca59SPeter Maydell }; 23059546ca59SPeter Maydell 23069546ca59SPeter Maydell return do_long_3d(s, a, opfn[a->size], accfn[a->size]); 23079546ca59SPeter Maydell } 230818fb58d5SPeter Maydell 230918fb58d5SPeter Maydell static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) 231018fb58d5SPeter Maydell { 231118fb58d5SPeter Maydell gen_helper_gvec_3 *fn_gvec; 231218fb58d5SPeter Maydell 231318fb58d5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 231418fb58d5SPeter Maydell return false; 231518fb58d5SPeter Maydell } 231618fb58d5SPeter Maydell 231718fb58d5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 231818fb58d5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 231918fb58d5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 232018fb58d5SPeter Maydell return false; 232118fb58d5SPeter Maydell } 232218fb58d5SPeter Maydell 232318fb58d5SPeter Maydell if (a->vd & 1) { 232418fb58d5SPeter Maydell return false; 232518fb58d5SPeter Maydell } 232618fb58d5SPeter Maydell 232718fb58d5SPeter Maydell switch (a->size) { 232818fb58d5SPeter Maydell case 0: 232918fb58d5SPeter Maydell fn_gvec = gen_helper_neon_pmull_h; 233018fb58d5SPeter Maydell break; 233118fb58d5SPeter Maydell case 2: 233218fb58d5SPeter Maydell if (!dc_isar_feature(aa32_pmull, s)) { 233318fb58d5SPeter Maydell return false; 233418fb58d5SPeter Maydell } 233518fb58d5SPeter Maydell fn_gvec = gen_helper_gvec_pmull_q; 233618fb58d5SPeter Maydell break; 233718fb58d5SPeter Maydell default: 233818fb58d5SPeter Maydell return false; 233918fb58d5SPeter Maydell } 234018fb58d5SPeter Maydell 234118fb58d5SPeter Maydell if (!vfp_access_check(s)) { 234218fb58d5SPeter Maydell return true; 234318fb58d5SPeter Maydell } 234418fb58d5SPeter Maydell 234518fb58d5SPeter Maydell tcg_gen_gvec_3_ool(neon_reg_offset(a->vd, 0), 234618fb58d5SPeter Maydell neon_reg_offset(a->vn, 0), 234718fb58d5SPeter Maydell neon_reg_offset(a->vm, 0), 234818fb58d5SPeter Maydell 16, 16, 0, fn_gvec); 234918fb58d5SPeter Maydell return true; 235018fb58d5SPeter Maydell } 235196fc80f5SPeter Maydell 235296fc80f5SPeter Maydell static void gen_neon_dup_low16(TCGv_i32 var) 235396fc80f5SPeter Maydell { 235496fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 235596fc80f5SPeter Maydell tcg_gen_ext16u_i32(var, var); 235696fc80f5SPeter Maydell tcg_gen_shli_i32(tmp, var, 16); 235796fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 235896fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 235996fc80f5SPeter Maydell } 236096fc80f5SPeter Maydell 236196fc80f5SPeter Maydell static void gen_neon_dup_high16(TCGv_i32 var) 236296fc80f5SPeter Maydell { 236396fc80f5SPeter Maydell TCGv_i32 tmp = tcg_temp_new_i32(); 236496fc80f5SPeter Maydell tcg_gen_andi_i32(var, var, 0xffff0000); 236596fc80f5SPeter Maydell tcg_gen_shri_i32(tmp, var, 16); 236696fc80f5SPeter Maydell tcg_gen_or_i32(var, var, tmp); 236796fc80f5SPeter Maydell tcg_temp_free_i32(tmp); 236896fc80f5SPeter Maydell } 236996fc80f5SPeter Maydell 237096fc80f5SPeter Maydell static inline TCGv_i32 neon_get_scalar(int size, int reg) 237196fc80f5SPeter Maydell { 237296fc80f5SPeter Maydell TCGv_i32 tmp; 237396fc80f5SPeter Maydell if (size == 1) { 237496fc80f5SPeter Maydell tmp = neon_load_reg(reg & 7, reg >> 4); 237596fc80f5SPeter Maydell if (reg & 8) { 237696fc80f5SPeter Maydell gen_neon_dup_high16(tmp); 237796fc80f5SPeter Maydell } else { 237896fc80f5SPeter Maydell gen_neon_dup_low16(tmp); 237996fc80f5SPeter Maydell } 238096fc80f5SPeter Maydell } else { 238196fc80f5SPeter Maydell tmp = neon_load_reg(reg & 15, reg >> 4); 238296fc80f5SPeter Maydell } 238396fc80f5SPeter Maydell return tmp; 238496fc80f5SPeter Maydell } 238596fc80f5SPeter Maydell 238696fc80f5SPeter Maydell static bool do_2scalar(DisasContext *s, arg_2scalar *a, 238796fc80f5SPeter Maydell NeonGenTwoOpFn *opfn, NeonGenTwoOpFn *accfn) 238896fc80f5SPeter Maydell { 238996fc80f5SPeter Maydell /* 239096fc80f5SPeter Maydell * Two registers and a scalar: perform an operation between 239196fc80f5SPeter Maydell * the input elements and the scalar, and then possibly 239296fc80f5SPeter Maydell * perform an accumulation operation of that result into the 239396fc80f5SPeter Maydell * destination. 239496fc80f5SPeter Maydell */ 239596fc80f5SPeter Maydell TCGv_i32 scalar; 239696fc80f5SPeter Maydell int pass; 239796fc80f5SPeter Maydell 239896fc80f5SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 239996fc80f5SPeter Maydell return false; 240096fc80f5SPeter Maydell } 240196fc80f5SPeter Maydell 240296fc80f5SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 240396fc80f5SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 240496fc80f5SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 240596fc80f5SPeter Maydell return false; 240696fc80f5SPeter Maydell } 240796fc80f5SPeter Maydell 240896fc80f5SPeter Maydell if (!opfn) { 240996fc80f5SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 241096fc80f5SPeter Maydell return false; 241196fc80f5SPeter Maydell } 241296fc80f5SPeter Maydell 241396fc80f5SPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 241496fc80f5SPeter Maydell return false; 241596fc80f5SPeter Maydell } 241696fc80f5SPeter Maydell 241796fc80f5SPeter Maydell if (!vfp_access_check(s)) { 241896fc80f5SPeter Maydell return true; 241996fc80f5SPeter Maydell } 242096fc80f5SPeter Maydell 242196fc80f5SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 242296fc80f5SPeter Maydell 242396fc80f5SPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 242496fc80f5SPeter Maydell TCGv_i32 tmp = neon_load_reg(a->vn, pass); 242596fc80f5SPeter Maydell opfn(tmp, tmp, scalar); 242696fc80f5SPeter Maydell if (accfn) { 242796fc80f5SPeter Maydell TCGv_i32 rd = neon_load_reg(a->vd, pass); 242896fc80f5SPeter Maydell accfn(tmp, rd, tmp); 242996fc80f5SPeter Maydell tcg_temp_free_i32(rd); 243096fc80f5SPeter Maydell } 243196fc80f5SPeter Maydell neon_store_reg(a->vd, pass, tmp); 243296fc80f5SPeter Maydell } 243396fc80f5SPeter Maydell tcg_temp_free_i32(scalar); 243496fc80f5SPeter Maydell return true; 243596fc80f5SPeter Maydell } 243696fc80f5SPeter Maydell 243796fc80f5SPeter Maydell static bool trans_VMUL_2sc(DisasContext *s, arg_2scalar *a) 243896fc80f5SPeter Maydell { 243996fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 244096fc80f5SPeter Maydell NULL, 244196fc80f5SPeter Maydell gen_helper_neon_mul_u16, 244296fc80f5SPeter Maydell tcg_gen_mul_i32, 244396fc80f5SPeter Maydell NULL, 244496fc80f5SPeter Maydell }; 244596fc80f5SPeter Maydell 244696fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 244796fc80f5SPeter Maydell } 244896fc80f5SPeter Maydell 244996fc80f5SPeter Maydell static bool trans_VMLA_2sc(DisasContext *s, arg_2scalar *a) 245096fc80f5SPeter Maydell { 245196fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 245296fc80f5SPeter Maydell NULL, 245396fc80f5SPeter Maydell gen_helper_neon_mul_u16, 245496fc80f5SPeter Maydell tcg_gen_mul_i32, 245596fc80f5SPeter Maydell NULL, 245696fc80f5SPeter Maydell }; 245796fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 245896fc80f5SPeter Maydell NULL, 245996fc80f5SPeter Maydell gen_helper_neon_add_u16, 246096fc80f5SPeter Maydell tcg_gen_add_i32, 246196fc80f5SPeter Maydell NULL, 246296fc80f5SPeter Maydell }; 246396fc80f5SPeter Maydell 246496fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 246596fc80f5SPeter Maydell } 246696fc80f5SPeter Maydell 246796fc80f5SPeter Maydell static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a) 246896fc80f5SPeter Maydell { 246996fc80f5SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 247096fc80f5SPeter Maydell NULL, 247196fc80f5SPeter Maydell gen_helper_neon_mul_u16, 247296fc80f5SPeter Maydell tcg_gen_mul_i32, 247396fc80f5SPeter Maydell NULL, 247496fc80f5SPeter Maydell }; 247596fc80f5SPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 247696fc80f5SPeter Maydell NULL, 247796fc80f5SPeter Maydell gen_helper_neon_sub_u16, 247896fc80f5SPeter Maydell tcg_gen_sub_i32, 247996fc80f5SPeter Maydell NULL, 248096fc80f5SPeter Maydell }; 248196fc80f5SPeter Maydell 248296fc80f5SPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 248396fc80f5SPeter Maydell } 248485ac9aefSPeter Maydell 248585ac9aefSPeter Maydell /* 248685ac9aefSPeter Maydell * Rather than have a float-specific version of do_2scalar just for 248785ac9aefSPeter Maydell * three insns, we wrap a NeonGenTwoSingleOpFn to turn it into 248885ac9aefSPeter Maydell * a NeonGenTwoOpFn. 248985ac9aefSPeter Maydell */ 249085ac9aefSPeter Maydell #define WRAP_FP_FN(WRAPNAME, FUNC) \ 249185ac9aefSPeter Maydell static void WRAPNAME(TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \ 249285ac9aefSPeter Maydell { \ 249385ac9aefSPeter Maydell TCGv_ptr fpstatus = get_fpstatus_ptr(1); \ 249485ac9aefSPeter Maydell FUNC(rd, rn, rm, fpstatus); \ 249585ac9aefSPeter Maydell tcg_temp_free_ptr(fpstatus); \ 249685ac9aefSPeter Maydell } 249785ac9aefSPeter Maydell 249885ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls) 249985ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds) 250085ac9aefSPeter Maydell WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs) 250185ac9aefSPeter Maydell 250285ac9aefSPeter Maydell static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a) 250385ac9aefSPeter Maydell { 250485ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 250585ac9aefSPeter Maydell NULL, 250685ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 250785ac9aefSPeter Maydell gen_VMUL_F_mul, 250885ac9aefSPeter Maydell NULL, 250985ac9aefSPeter Maydell }; 251085ac9aefSPeter Maydell 251185ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 251285ac9aefSPeter Maydell } 251385ac9aefSPeter Maydell 251485ac9aefSPeter Maydell static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a) 251585ac9aefSPeter Maydell { 251685ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 251785ac9aefSPeter Maydell NULL, 251885ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 251985ac9aefSPeter Maydell gen_VMUL_F_mul, 252085ac9aefSPeter Maydell NULL, 252185ac9aefSPeter Maydell }; 252285ac9aefSPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 252385ac9aefSPeter Maydell NULL, 252485ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 252585ac9aefSPeter Maydell gen_VMUL_F_add, 252685ac9aefSPeter Maydell NULL, 252785ac9aefSPeter Maydell }; 252885ac9aefSPeter Maydell 252985ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 253085ac9aefSPeter Maydell } 253185ac9aefSPeter Maydell 253285ac9aefSPeter Maydell static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a) 253385ac9aefSPeter Maydell { 253485ac9aefSPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 253585ac9aefSPeter Maydell NULL, 253685ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 253785ac9aefSPeter Maydell gen_VMUL_F_mul, 253885ac9aefSPeter Maydell NULL, 253985ac9aefSPeter Maydell }; 254085ac9aefSPeter Maydell static NeonGenTwoOpFn * const accfn[] = { 254185ac9aefSPeter Maydell NULL, 254285ac9aefSPeter Maydell NULL, /* TODO: fp16 support */ 254385ac9aefSPeter Maydell gen_VMUL_F_sub, 254485ac9aefSPeter Maydell NULL, 254585ac9aefSPeter Maydell }; 254685ac9aefSPeter Maydell 254785ac9aefSPeter Maydell return do_2scalar(s, a, opfn[a->size], accfn[a->size]); 254885ac9aefSPeter Maydell } 2549b2fc7be9SPeter Maydell 2550b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16) 2551b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32) 2552b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_16, gen_helper_neon_qrdmulh_s16) 2553b2fc7be9SPeter Maydell WRAP_ENV_FN(gen_VQRDMULH_32, gen_helper_neon_qrdmulh_s32) 2554b2fc7be9SPeter Maydell 2555b2fc7be9SPeter Maydell static bool trans_VQDMULH_2sc(DisasContext *s, arg_2scalar *a) 2556b2fc7be9SPeter Maydell { 2557b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2558b2fc7be9SPeter Maydell NULL, 2559b2fc7be9SPeter Maydell gen_VQDMULH_16, 2560b2fc7be9SPeter Maydell gen_VQDMULH_32, 2561b2fc7be9SPeter Maydell NULL, 2562b2fc7be9SPeter Maydell }; 2563b2fc7be9SPeter Maydell 2564b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2565b2fc7be9SPeter Maydell } 2566b2fc7be9SPeter Maydell 2567b2fc7be9SPeter Maydell static bool trans_VQRDMULH_2sc(DisasContext *s, arg_2scalar *a) 2568b2fc7be9SPeter Maydell { 2569b2fc7be9SPeter Maydell static NeonGenTwoOpFn * const opfn[] = { 2570b2fc7be9SPeter Maydell NULL, 2571b2fc7be9SPeter Maydell gen_VQRDMULH_16, 2572b2fc7be9SPeter Maydell gen_VQRDMULH_32, 2573b2fc7be9SPeter Maydell NULL, 2574b2fc7be9SPeter Maydell }; 2575b2fc7be9SPeter Maydell 2576b2fc7be9SPeter Maydell return do_2scalar(s, a, opfn[a->size], NULL); 2577b2fc7be9SPeter Maydell } 2578aa318f5bSPeter Maydell 2579aa318f5bSPeter Maydell static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, 2580aa318f5bSPeter Maydell NeonGenThreeOpEnvFn *opfn) 2581aa318f5bSPeter Maydell { 2582aa318f5bSPeter Maydell /* 2583aa318f5bSPeter Maydell * VQRDMLAH/VQRDMLSH: this is like do_2scalar, but the opfn 2584aa318f5bSPeter Maydell * performs a kind of fused op-then-accumulate using a helper 2585aa318f5bSPeter Maydell * function that takes all of rd, rn and the scalar at once. 2586aa318f5bSPeter Maydell */ 2587aa318f5bSPeter Maydell TCGv_i32 scalar; 2588aa318f5bSPeter Maydell int pass; 2589aa318f5bSPeter Maydell 2590aa318f5bSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2591aa318f5bSPeter Maydell return false; 2592aa318f5bSPeter Maydell } 2593aa318f5bSPeter Maydell 2594aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_rdm, s)) { 2595aa318f5bSPeter Maydell return false; 2596aa318f5bSPeter Maydell } 2597aa318f5bSPeter Maydell 2598aa318f5bSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2599aa318f5bSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2600aa318f5bSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 2601aa318f5bSPeter Maydell return false; 2602aa318f5bSPeter Maydell } 2603aa318f5bSPeter Maydell 2604aa318f5bSPeter Maydell if (!opfn) { 2605aa318f5bSPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 2606aa318f5bSPeter Maydell return false; 2607aa318f5bSPeter Maydell } 2608aa318f5bSPeter Maydell 2609aa318f5bSPeter Maydell if (a->q && ((a->vd | a->vn) & 1)) { 2610aa318f5bSPeter Maydell return false; 2611aa318f5bSPeter Maydell } 2612aa318f5bSPeter Maydell 2613aa318f5bSPeter Maydell if (!vfp_access_check(s)) { 2614aa318f5bSPeter Maydell return true; 2615aa318f5bSPeter Maydell } 2616aa318f5bSPeter Maydell 2617aa318f5bSPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 2618aa318f5bSPeter Maydell 2619aa318f5bSPeter Maydell for (pass = 0; pass < (a->q ? 4 : 2); pass++) { 2620aa318f5bSPeter Maydell TCGv_i32 rn = neon_load_reg(a->vn, pass); 2621aa318f5bSPeter Maydell TCGv_i32 rd = neon_load_reg(a->vd, pass); 2622aa318f5bSPeter Maydell opfn(rd, cpu_env, rn, scalar, rd); 2623aa318f5bSPeter Maydell tcg_temp_free_i32(rn); 2624aa318f5bSPeter Maydell neon_store_reg(a->vd, pass, rd); 2625aa318f5bSPeter Maydell } 2626aa318f5bSPeter Maydell tcg_temp_free_i32(scalar); 2627aa318f5bSPeter Maydell 2628aa318f5bSPeter Maydell return true; 2629aa318f5bSPeter Maydell } 2630aa318f5bSPeter Maydell 2631aa318f5bSPeter Maydell static bool trans_VQRDMLAH_2sc(DisasContext *s, arg_2scalar *a) 2632aa318f5bSPeter Maydell { 2633aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2634aa318f5bSPeter Maydell NULL, 2635aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s16, 2636aa318f5bSPeter Maydell gen_helper_neon_qrdmlah_s32, 2637aa318f5bSPeter Maydell NULL, 2638aa318f5bSPeter Maydell }; 2639aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2640aa318f5bSPeter Maydell } 2641aa318f5bSPeter Maydell 2642aa318f5bSPeter Maydell static bool trans_VQRDMLSH_2sc(DisasContext *s, arg_2scalar *a) 2643aa318f5bSPeter Maydell { 2644aa318f5bSPeter Maydell static NeonGenThreeOpEnvFn *opfn[] = { 2645aa318f5bSPeter Maydell NULL, 2646aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s16, 2647aa318f5bSPeter Maydell gen_helper_neon_qrdmlsh_s32, 2648aa318f5bSPeter Maydell NULL, 2649aa318f5bSPeter Maydell }; 2650aa318f5bSPeter Maydell return do_vqrdmlah_2sc(s, a, opfn[a->size]); 2651aa318f5bSPeter Maydell } 265277e576a9SPeter Maydell 265377e576a9SPeter Maydell static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, 265477e576a9SPeter Maydell NeonGenTwoOpWidenFn *opfn, 265577e576a9SPeter Maydell NeonGenTwo64OpFn *accfn) 265677e576a9SPeter Maydell { 265777e576a9SPeter Maydell /* 265877e576a9SPeter Maydell * Two registers and a scalar, long operations: perform an 265977e576a9SPeter Maydell * operation on the input elements and the scalar which produces 266077e576a9SPeter Maydell * a double-width result, and then possibly perform an accumulation 266177e576a9SPeter Maydell * operation of that result into the destination. 266277e576a9SPeter Maydell */ 266377e576a9SPeter Maydell TCGv_i32 scalar, rn; 266477e576a9SPeter Maydell TCGv_i64 rn0_64, rn1_64; 266577e576a9SPeter Maydell 266677e576a9SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 266777e576a9SPeter Maydell return false; 266877e576a9SPeter Maydell } 266977e576a9SPeter Maydell 267077e576a9SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 267177e576a9SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 267277e576a9SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 267377e576a9SPeter Maydell return false; 267477e576a9SPeter Maydell } 267577e576a9SPeter Maydell 267677e576a9SPeter Maydell if (!opfn) { 267777e576a9SPeter Maydell /* Bad size (including size == 3, which is a different insn group) */ 267877e576a9SPeter Maydell return false; 267977e576a9SPeter Maydell } 268077e576a9SPeter Maydell 268177e576a9SPeter Maydell if (a->vd & 1) { 268277e576a9SPeter Maydell return false; 268377e576a9SPeter Maydell } 268477e576a9SPeter Maydell 268577e576a9SPeter Maydell if (!vfp_access_check(s)) { 268677e576a9SPeter Maydell return true; 268777e576a9SPeter Maydell } 268877e576a9SPeter Maydell 268977e576a9SPeter Maydell scalar = neon_get_scalar(a->size, a->vm); 269077e576a9SPeter Maydell 269177e576a9SPeter Maydell /* Load all inputs before writing any outputs, in case of overlap */ 269277e576a9SPeter Maydell rn = neon_load_reg(a->vn, 0); 269377e576a9SPeter Maydell rn0_64 = tcg_temp_new_i64(); 269477e576a9SPeter Maydell opfn(rn0_64, rn, scalar); 269577e576a9SPeter Maydell tcg_temp_free_i32(rn); 269677e576a9SPeter Maydell 269777e576a9SPeter Maydell rn = neon_load_reg(a->vn, 1); 269877e576a9SPeter Maydell rn1_64 = tcg_temp_new_i64(); 269977e576a9SPeter Maydell opfn(rn1_64, rn, scalar); 270077e576a9SPeter Maydell tcg_temp_free_i32(rn); 270177e576a9SPeter Maydell tcg_temp_free_i32(scalar); 270277e576a9SPeter Maydell 270377e576a9SPeter Maydell if (accfn) { 270477e576a9SPeter Maydell TCGv_i64 t64 = tcg_temp_new_i64(); 270577e576a9SPeter Maydell neon_load_reg64(t64, a->vd); 270677e576a9SPeter Maydell accfn(t64, t64, rn0_64); 270777e576a9SPeter Maydell neon_store_reg64(t64, a->vd); 270877e576a9SPeter Maydell neon_load_reg64(t64, a->vd + 1); 270977e576a9SPeter Maydell accfn(t64, t64, rn1_64); 271077e576a9SPeter Maydell neon_store_reg64(t64, a->vd + 1); 271177e576a9SPeter Maydell tcg_temp_free_i64(t64); 271277e576a9SPeter Maydell } else { 271377e576a9SPeter Maydell neon_store_reg64(rn0_64, a->vd); 271477e576a9SPeter Maydell neon_store_reg64(rn1_64, a->vd + 1); 271577e576a9SPeter Maydell } 271677e576a9SPeter Maydell tcg_temp_free_i64(rn0_64); 271777e576a9SPeter Maydell tcg_temp_free_i64(rn1_64); 271877e576a9SPeter Maydell return true; 271977e576a9SPeter Maydell } 272077e576a9SPeter Maydell 272177e576a9SPeter Maydell static bool trans_VMULL_S_2sc(DisasContext *s, arg_2scalar *a) 272277e576a9SPeter Maydell { 272377e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 272477e576a9SPeter Maydell NULL, 272577e576a9SPeter Maydell gen_helper_neon_mull_s16, 272677e576a9SPeter Maydell gen_mull_s32, 272777e576a9SPeter Maydell NULL, 272877e576a9SPeter Maydell }; 272977e576a9SPeter Maydell 273077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 273177e576a9SPeter Maydell } 273277e576a9SPeter Maydell 273377e576a9SPeter Maydell static bool trans_VMULL_U_2sc(DisasContext *s, arg_2scalar *a) 273477e576a9SPeter Maydell { 273577e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 273677e576a9SPeter Maydell NULL, 273777e576a9SPeter Maydell gen_helper_neon_mull_u16, 273877e576a9SPeter Maydell gen_mull_u32, 273977e576a9SPeter Maydell NULL, 274077e576a9SPeter Maydell }; 274177e576a9SPeter Maydell 274277e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 274377e576a9SPeter Maydell } 274477e576a9SPeter Maydell 274577e576a9SPeter Maydell #define DO_VMLAL_2SC(INSN, MULL, ACC) \ 274677e576a9SPeter Maydell static bool trans_##INSN##_2sc(DisasContext *s, arg_2scalar *a) \ 274777e576a9SPeter Maydell { \ 274877e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { \ 274977e576a9SPeter Maydell NULL, \ 275077e576a9SPeter Maydell gen_helper_neon_##MULL##16, \ 275177e576a9SPeter Maydell gen_##MULL##32, \ 275277e576a9SPeter Maydell NULL, \ 275377e576a9SPeter Maydell }; \ 275477e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { \ 275577e576a9SPeter Maydell NULL, \ 275677e576a9SPeter Maydell gen_helper_neon_##ACC##l_u32, \ 275777e576a9SPeter Maydell tcg_gen_##ACC##_i64, \ 275877e576a9SPeter Maydell NULL, \ 275977e576a9SPeter Maydell }; \ 276077e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); \ 276177e576a9SPeter Maydell } 276277e576a9SPeter Maydell 276377e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_S, mull_s, add) 276477e576a9SPeter Maydell DO_VMLAL_2SC(VMLAL_U, mull_u, add) 276577e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_S, mull_s, sub) 276677e576a9SPeter Maydell DO_VMLAL_2SC(VMLSL_U, mull_u, sub) 276777e576a9SPeter Maydell 276877e576a9SPeter Maydell static bool trans_VQDMULL_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 277777e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], NULL); 277877e576a9SPeter Maydell } 277977e576a9SPeter Maydell 278077e576a9SPeter Maydell static bool trans_VQDMLAL_2sc(DisasContext *s, arg_2scalar *a) 278177e576a9SPeter Maydell { 278277e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 278377e576a9SPeter Maydell NULL, 278477e576a9SPeter Maydell gen_VQDMULL_16, 278577e576a9SPeter Maydell gen_VQDMULL_32, 278677e576a9SPeter Maydell NULL, 278777e576a9SPeter Maydell }; 278877e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 278977e576a9SPeter Maydell NULL, 279077e576a9SPeter Maydell gen_VQDMLAL_acc_16, 279177e576a9SPeter Maydell gen_VQDMLAL_acc_32, 279277e576a9SPeter Maydell NULL, 279377e576a9SPeter Maydell }; 279477e576a9SPeter Maydell 279577e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 279677e576a9SPeter Maydell } 279777e576a9SPeter Maydell 279877e576a9SPeter Maydell static bool trans_VQDMLSL_2sc(DisasContext *s, arg_2scalar *a) 279977e576a9SPeter Maydell { 280077e576a9SPeter Maydell static NeonGenTwoOpWidenFn * const opfn[] = { 280177e576a9SPeter Maydell NULL, 280277e576a9SPeter Maydell gen_VQDMULL_16, 280377e576a9SPeter Maydell gen_VQDMULL_32, 280477e576a9SPeter Maydell NULL, 280577e576a9SPeter Maydell }; 280677e576a9SPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 280777e576a9SPeter Maydell NULL, 280877e576a9SPeter Maydell gen_VQDMLSL_acc_16, 280977e576a9SPeter Maydell gen_VQDMLSL_acc_32, 281077e576a9SPeter Maydell NULL, 281177e576a9SPeter Maydell }; 281277e576a9SPeter Maydell 281377e576a9SPeter Maydell return do_2scalar_long(s, a, opfn[a->size], accfn[a->size]); 281477e576a9SPeter Maydell } 28150aad761fSPeter Maydell 28160aad761fSPeter Maydell static bool trans_VEXT(DisasContext *s, arg_VEXT *a) 28170aad761fSPeter Maydell { 28180aad761fSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 28190aad761fSPeter Maydell return false; 28200aad761fSPeter Maydell } 28210aad761fSPeter Maydell 28220aad761fSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 28230aad761fSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 28240aad761fSPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 28250aad761fSPeter Maydell return false; 28260aad761fSPeter Maydell } 28270aad761fSPeter Maydell 28280aad761fSPeter Maydell if ((a->vn | a->vm | a->vd) & a->q) { 28290aad761fSPeter Maydell return false; 28300aad761fSPeter Maydell } 28310aad761fSPeter Maydell 28320aad761fSPeter Maydell if (a->imm > 7 && !a->q) { 28330aad761fSPeter Maydell return false; 28340aad761fSPeter Maydell } 28350aad761fSPeter Maydell 28360aad761fSPeter Maydell if (!vfp_access_check(s)) { 28370aad761fSPeter Maydell return true; 28380aad761fSPeter Maydell } 28390aad761fSPeter Maydell 28400aad761fSPeter Maydell if (!a->q) { 28410aad761fSPeter Maydell /* Extract 64 bits from <Vm:Vn> */ 28420aad761fSPeter Maydell TCGv_i64 left, right, dest; 28430aad761fSPeter Maydell 28440aad761fSPeter Maydell left = tcg_temp_new_i64(); 28450aad761fSPeter Maydell right = tcg_temp_new_i64(); 28460aad761fSPeter Maydell dest = tcg_temp_new_i64(); 28470aad761fSPeter Maydell 28480aad761fSPeter Maydell neon_load_reg64(right, a->vn); 28490aad761fSPeter Maydell neon_load_reg64(left, a->vm); 28500aad761fSPeter Maydell tcg_gen_extract2_i64(dest, right, left, a->imm * 8); 28510aad761fSPeter Maydell neon_store_reg64(dest, a->vd); 28520aad761fSPeter Maydell 28530aad761fSPeter Maydell tcg_temp_free_i64(left); 28540aad761fSPeter Maydell tcg_temp_free_i64(right); 28550aad761fSPeter Maydell tcg_temp_free_i64(dest); 28560aad761fSPeter Maydell } else { 28570aad761fSPeter Maydell /* Extract 128 bits from <Vm+1:Vm:Vn+1:Vn> */ 28580aad761fSPeter Maydell TCGv_i64 left, middle, right, destleft, destright; 28590aad761fSPeter Maydell 28600aad761fSPeter Maydell left = tcg_temp_new_i64(); 28610aad761fSPeter Maydell middle = tcg_temp_new_i64(); 28620aad761fSPeter Maydell right = tcg_temp_new_i64(); 28630aad761fSPeter Maydell destleft = tcg_temp_new_i64(); 28640aad761fSPeter Maydell destright = tcg_temp_new_i64(); 28650aad761fSPeter Maydell 28660aad761fSPeter Maydell if (a->imm < 8) { 28670aad761fSPeter Maydell neon_load_reg64(right, a->vn); 28680aad761fSPeter Maydell neon_load_reg64(middle, a->vn + 1); 28690aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, a->imm * 8); 28700aad761fSPeter Maydell neon_load_reg64(left, a->vm); 28710aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, a->imm * 8); 28720aad761fSPeter Maydell } else { 28730aad761fSPeter Maydell neon_load_reg64(right, a->vn + 1); 28740aad761fSPeter Maydell neon_load_reg64(middle, a->vm); 28750aad761fSPeter Maydell tcg_gen_extract2_i64(destright, right, middle, (a->imm - 8) * 8); 28760aad761fSPeter Maydell neon_load_reg64(left, a->vm + 1); 28770aad761fSPeter Maydell tcg_gen_extract2_i64(destleft, middle, left, (a->imm - 8) * 8); 28780aad761fSPeter Maydell } 28790aad761fSPeter Maydell 28800aad761fSPeter Maydell neon_store_reg64(destright, a->vd); 28810aad761fSPeter Maydell neon_store_reg64(destleft, a->vd + 1); 28820aad761fSPeter Maydell 28830aad761fSPeter Maydell tcg_temp_free_i64(destright); 28840aad761fSPeter Maydell tcg_temp_free_i64(destleft); 28850aad761fSPeter Maydell tcg_temp_free_i64(right); 28860aad761fSPeter Maydell tcg_temp_free_i64(middle); 28870aad761fSPeter Maydell tcg_temp_free_i64(left); 28880aad761fSPeter Maydell } 28890aad761fSPeter Maydell return true; 28900aad761fSPeter Maydell } 289154e96c74SPeter Maydell 289254e96c74SPeter Maydell static bool trans_VTBL(DisasContext *s, arg_VTBL *a) 289354e96c74SPeter Maydell { 289454e96c74SPeter Maydell int n; 289554e96c74SPeter Maydell TCGv_i32 tmp, tmp2, tmp3, tmp4; 289654e96c74SPeter Maydell TCGv_ptr ptr1; 289754e96c74SPeter Maydell 289854e96c74SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 289954e96c74SPeter Maydell return false; 290054e96c74SPeter Maydell } 290154e96c74SPeter Maydell 290254e96c74SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 290354e96c74SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 290454e96c74SPeter Maydell ((a->vd | a->vn | a->vm) & 0x10)) { 290554e96c74SPeter Maydell return false; 290654e96c74SPeter Maydell } 290754e96c74SPeter Maydell 290854e96c74SPeter Maydell if (!vfp_access_check(s)) { 290954e96c74SPeter Maydell return true; 291054e96c74SPeter Maydell } 291154e96c74SPeter Maydell 291254e96c74SPeter Maydell n = a->len + 1; 291354e96c74SPeter Maydell if ((a->vn + n) > 32) { 291454e96c74SPeter Maydell /* 291554e96c74SPeter Maydell * This is UNPREDICTABLE; we choose to UNDEF to avoid the 291654e96c74SPeter Maydell * helper function running off the end of the register file. 291754e96c74SPeter Maydell */ 291854e96c74SPeter Maydell return false; 291954e96c74SPeter Maydell } 292054e96c74SPeter Maydell n <<= 3; 292154e96c74SPeter Maydell if (a->op) { 292254e96c74SPeter Maydell tmp = neon_load_reg(a->vd, 0); 292354e96c74SPeter Maydell } else { 292454e96c74SPeter Maydell tmp = tcg_temp_new_i32(); 292554e96c74SPeter Maydell tcg_gen_movi_i32(tmp, 0); 292654e96c74SPeter Maydell } 292754e96c74SPeter Maydell tmp2 = neon_load_reg(a->vm, 0); 292854e96c74SPeter Maydell ptr1 = vfp_reg_ptr(true, a->vn); 292954e96c74SPeter Maydell tmp4 = tcg_const_i32(n); 293054e96c74SPeter Maydell gen_helper_neon_tbl(tmp2, tmp2, tmp, ptr1, tmp4); 293154e96c74SPeter Maydell tcg_temp_free_i32(tmp); 293254e96c74SPeter Maydell if (a->op) { 293354e96c74SPeter Maydell tmp = neon_load_reg(a->vd, 1); 293454e96c74SPeter Maydell } else { 293554e96c74SPeter Maydell tmp = tcg_temp_new_i32(); 293654e96c74SPeter Maydell tcg_gen_movi_i32(tmp, 0); 293754e96c74SPeter Maydell } 293854e96c74SPeter Maydell tmp3 = neon_load_reg(a->vm, 1); 293954e96c74SPeter Maydell gen_helper_neon_tbl(tmp3, tmp3, tmp, ptr1, tmp4); 294054e96c74SPeter Maydell tcg_temp_free_i32(tmp4); 294154e96c74SPeter Maydell tcg_temp_free_ptr(ptr1); 294254e96c74SPeter Maydell neon_store_reg(a->vd, 0, tmp2); 294354e96c74SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 294454e96c74SPeter Maydell tcg_temp_free_i32(tmp); 294554e96c74SPeter Maydell return true; 294654e96c74SPeter Maydell } 29479aaa23c2SPeter Maydell 29489aaa23c2SPeter Maydell static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) 29499aaa23c2SPeter Maydell { 29509aaa23c2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 29519aaa23c2SPeter Maydell return false; 29529aaa23c2SPeter Maydell } 29539aaa23c2SPeter Maydell 29549aaa23c2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 29559aaa23c2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 29569aaa23c2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 29579aaa23c2SPeter Maydell return false; 29589aaa23c2SPeter Maydell } 29599aaa23c2SPeter Maydell 29609aaa23c2SPeter Maydell if (a->vd & a->q) { 29619aaa23c2SPeter Maydell return false; 29629aaa23c2SPeter Maydell } 29639aaa23c2SPeter Maydell 29649aaa23c2SPeter Maydell if (!vfp_access_check(s)) { 29659aaa23c2SPeter Maydell return true; 29669aaa23c2SPeter Maydell } 29679aaa23c2SPeter Maydell 29689aaa23c2SPeter Maydell tcg_gen_gvec_dup_mem(a->size, neon_reg_offset(a->vd, 0), 29699aaa23c2SPeter Maydell neon_element_offset(a->vm, a->index, a->size), 29709aaa23c2SPeter Maydell a->q ? 16 : 8, a->q ? 16 : 8); 29719aaa23c2SPeter Maydell return true; 29729aaa23c2SPeter Maydell } 2973353d2b85SPeter Maydell 2974353d2b85SPeter Maydell static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) 2975353d2b85SPeter Maydell { 2976353d2b85SPeter Maydell int pass, half; 2977353d2b85SPeter Maydell 2978353d2b85SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 2979353d2b85SPeter Maydell return false; 2980353d2b85SPeter Maydell } 2981353d2b85SPeter Maydell 2982353d2b85SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 2983353d2b85SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 2984353d2b85SPeter Maydell ((a->vd | a->vm) & 0x10)) { 2985353d2b85SPeter Maydell return false; 2986353d2b85SPeter Maydell } 2987353d2b85SPeter Maydell 2988353d2b85SPeter Maydell if ((a->vd | a->vm) & a->q) { 2989353d2b85SPeter Maydell return false; 2990353d2b85SPeter Maydell } 2991353d2b85SPeter Maydell 2992353d2b85SPeter Maydell if (a->size == 3) { 2993353d2b85SPeter Maydell return false; 2994353d2b85SPeter Maydell } 2995353d2b85SPeter Maydell 2996353d2b85SPeter Maydell if (!vfp_access_check(s)) { 2997353d2b85SPeter Maydell return true; 2998353d2b85SPeter Maydell } 2999353d2b85SPeter Maydell 3000353d2b85SPeter Maydell for (pass = 0; pass < (a->q ? 2 : 1); pass++) { 3001353d2b85SPeter Maydell TCGv_i32 tmp[2]; 3002353d2b85SPeter Maydell 3003353d2b85SPeter Maydell for (half = 0; half < 2; half++) { 3004353d2b85SPeter Maydell tmp[half] = neon_load_reg(a->vm, pass * 2 + half); 3005353d2b85SPeter Maydell switch (a->size) { 3006353d2b85SPeter Maydell case 0: 3007353d2b85SPeter Maydell tcg_gen_bswap32_i32(tmp[half], tmp[half]); 3008353d2b85SPeter Maydell break; 3009353d2b85SPeter Maydell case 1: 3010353d2b85SPeter Maydell gen_swap_half(tmp[half]); 3011353d2b85SPeter Maydell break; 3012353d2b85SPeter Maydell case 2: 3013353d2b85SPeter Maydell break; 3014353d2b85SPeter Maydell default: 3015353d2b85SPeter Maydell g_assert_not_reached(); 3016353d2b85SPeter Maydell } 3017353d2b85SPeter Maydell } 3018353d2b85SPeter Maydell neon_store_reg(a->vd, pass * 2, tmp[1]); 3019353d2b85SPeter Maydell neon_store_reg(a->vd, pass * 2 + 1, tmp[0]); 3020353d2b85SPeter Maydell } 3021353d2b85SPeter Maydell return true; 3022353d2b85SPeter Maydell } 30236106af3aSPeter Maydell 30246106af3aSPeter Maydell static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, 30256106af3aSPeter Maydell NeonGenWidenFn *widenfn, 30266106af3aSPeter Maydell NeonGenTwo64OpFn *opfn, 30276106af3aSPeter Maydell NeonGenTwo64OpFn *accfn) 30286106af3aSPeter Maydell { 30296106af3aSPeter Maydell /* 30306106af3aSPeter Maydell * Pairwise long operations: widen both halves of the pair, 30316106af3aSPeter Maydell * combine the pairs with the opfn, and then possibly accumulate 30326106af3aSPeter Maydell * into the destination with the accfn. 30336106af3aSPeter Maydell */ 30346106af3aSPeter Maydell int pass; 30356106af3aSPeter Maydell 30366106af3aSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 30376106af3aSPeter Maydell return false; 30386106af3aSPeter Maydell } 30396106af3aSPeter Maydell 30406106af3aSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 30416106af3aSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 30426106af3aSPeter Maydell ((a->vd | a->vm) & 0x10)) { 30436106af3aSPeter Maydell return false; 30446106af3aSPeter Maydell } 30456106af3aSPeter Maydell 30466106af3aSPeter Maydell if ((a->vd | a->vm) & a->q) { 30476106af3aSPeter Maydell return false; 30486106af3aSPeter Maydell } 30496106af3aSPeter Maydell 30506106af3aSPeter Maydell if (!widenfn) { 30516106af3aSPeter Maydell return false; 30526106af3aSPeter Maydell } 30536106af3aSPeter Maydell 30546106af3aSPeter Maydell if (!vfp_access_check(s)) { 30556106af3aSPeter Maydell return true; 30566106af3aSPeter Maydell } 30576106af3aSPeter Maydell 30586106af3aSPeter Maydell for (pass = 0; pass < a->q + 1; pass++) { 30596106af3aSPeter Maydell TCGv_i32 tmp; 30606106af3aSPeter Maydell TCGv_i64 rm0_64, rm1_64, rd_64; 30616106af3aSPeter Maydell 30626106af3aSPeter Maydell rm0_64 = tcg_temp_new_i64(); 30636106af3aSPeter Maydell rm1_64 = tcg_temp_new_i64(); 30646106af3aSPeter Maydell rd_64 = tcg_temp_new_i64(); 30656106af3aSPeter Maydell tmp = neon_load_reg(a->vm, pass * 2); 30666106af3aSPeter Maydell widenfn(rm0_64, tmp); 30676106af3aSPeter Maydell tcg_temp_free_i32(tmp); 30686106af3aSPeter Maydell tmp = neon_load_reg(a->vm, pass * 2 + 1); 30696106af3aSPeter Maydell widenfn(rm1_64, tmp); 30706106af3aSPeter Maydell tcg_temp_free_i32(tmp); 30716106af3aSPeter Maydell opfn(rd_64, rm0_64, rm1_64); 30726106af3aSPeter Maydell tcg_temp_free_i64(rm0_64); 30736106af3aSPeter Maydell tcg_temp_free_i64(rm1_64); 30746106af3aSPeter Maydell 30756106af3aSPeter Maydell if (accfn) { 30766106af3aSPeter Maydell TCGv_i64 tmp64 = tcg_temp_new_i64(); 30776106af3aSPeter Maydell neon_load_reg64(tmp64, a->vd + pass); 30786106af3aSPeter Maydell accfn(rd_64, tmp64, rd_64); 30796106af3aSPeter Maydell tcg_temp_free_i64(tmp64); 30806106af3aSPeter Maydell } 30816106af3aSPeter Maydell neon_store_reg64(rd_64, a->vd + pass); 30826106af3aSPeter Maydell tcg_temp_free_i64(rd_64); 30836106af3aSPeter Maydell } 30846106af3aSPeter Maydell return true; 30856106af3aSPeter Maydell } 30866106af3aSPeter Maydell 30876106af3aSPeter Maydell static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) 30886106af3aSPeter Maydell { 30896106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 30906106af3aSPeter Maydell gen_helper_neon_widen_s8, 30916106af3aSPeter Maydell gen_helper_neon_widen_s16, 30926106af3aSPeter Maydell tcg_gen_ext_i32_i64, 30936106af3aSPeter Maydell NULL, 30946106af3aSPeter Maydell }; 30956106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 30966106af3aSPeter Maydell gen_helper_neon_paddl_u16, 30976106af3aSPeter Maydell gen_helper_neon_paddl_u32, 30986106af3aSPeter Maydell tcg_gen_add_i64, 30996106af3aSPeter Maydell NULL, 31006106af3aSPeter Maydell }; 31016106af3aSPeter Maydell 31026106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 31036106af3aSPeter Maydell } 31046106af3aSPeter Maydell 31056106af3aSPeter Maydell static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) 31066106af3aSPeter Maydell { 31076106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31086106af3aSPeter Maydell gen_helper_neon_widen_u8, 31096106af3aSPeter Maydell gen_helper_neon_widen_u16, 31106106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31116106af3aSPeter Maydell NULL, 31126106af3aSPeter Maydell }; 31136106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31146106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31156106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31166106af3aSPeter Maydell tcg_gen_add_i64, 31176106af3aSPeter Maydell NULL, 31186106af3aSPeter Maydell }; 31196106af3aSPeter Maydell 31206106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); 31216106af3aSPeter Maydell } 31226106af3aSPeter Maydell 31236106af3aSPeter Maydell static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) 31246106af3aSPeter Maydell { 31256106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31266106af3aSPeter Maydell gen_helper_neon_widen_s8, 31276106af3aSPeter Maydell gen_helper_neon_widen_s16, 31286106af3aSPeter Maydell tcg_gen_ext_i32_i64, 31296106af3aSPeter Maydell NULL, 31306106af3aSPeter Maydell }; 31316106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31326106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31336106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31346106af3aSPeter Maydell tcg_gen_add_i64, 31356106af3aSPeter Maydell NULL, 31366106af3aSPeter Maydell }; 31376106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31386106af3aSPeter Maydell gen_helper_neon_addl_u16, 31396106af3aSPeter Maydell gen_helper_neon_addl_u32, 31406106af3aSPeter Maydell tcg_gen_add_i64, 31416106af3aSPeter Maydell NULL, 31426106af3aSPeter Maydell }; 31436106af3aSPeter Maydell 31446106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31456106af3aSPeter Maydell accfn[a->size]); 31466106af3aSPeter Maydell } 31476106af3aSPeter Maydell 31486106af3aSPeter Maydell static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) 31496106af3aSPeter Maydell { 31506106af3aSPeter Maydell static NeonGenWidenFn * const widenfn[] = { 31516106af3aSPeter Maydell gen_helper_neon_widen_u8, 31526106af3aSPeter Maydell gen_helper_neon_widen_u16, 31536106af3aSPeter Maydell tcg_gen_extu_i32_i64, 31546106af3aSPeter Maydell NULL, 31556106af3aSPeter Maydell }; 31566106af3aSPeter Maydell static NeonGenTwo64OpFn * const opfn[] = { 31576106af3aSPeter Maydell gen_helper_neon_paddl_u16, 31586106af3aSPeter Maydell gen_helper_neon_paddl_u32, 31596106af3aSPeter Maydell tcg_gen_add_i64, 31606106af3aSPeter Maydell NULL, 31616106af3aSPeter Maydell }; 31626106af3aSPeter Maydell static NeonGenTwo64OpFn * const accfn[] = { 31636106af3aSPeter Maydell gen_helper_neon_addl_u16, 31646106af3aSPeter Maydell gen_helper_neon_addl_u32, 31656106af3aSPeter Maydell tcg_gen_add_i64, 31666106af3aSPeter Maydell NULL, 31676106af3aSPeter Maydell }; 31686106af3aSPeter Maydell 31696106af3aSPeter Maydell return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], 31706106af3aSPeter Maydell accfn[a->size]); 31716106af3aSPeter Maydell } 3172567663a2SPeter Maydell 3173567663a2SPeter Maydell typedef void ZipFn(TCGv_ptr, TCGv_ptr); 3174567663a2SPeter Maydell 3175567663a2SPeter Maydell static bool do_zip_uzp(DisasContext *s, arg_2misc *a, 3176567663a2SPeter Maydell ZipFn *fn) 3177567663a2SPeter Maydell { 3178567663a2SPeter Maydell TCGv_ptr pd, pm; 3179567663a2SPeter Maydell 3180567663a2SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3181567663a2SPeter Maydell return false; 3182567663a2SPeter Maydell } 3183567663a2SPeter Maydell 3184567663a2SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3185567663a2SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3186567663a2SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3187567663a2SPeter Maydell return false; 3188567663a2SPeter Maydell } 3189567663a2SPeter Maydell 3190567663a2SPeter Maydell if ((a->vd | a->vm) & a->q) { 3191567663a2SPeter Maydell return false; 3192567663a2SPeter Maydell } 3193567663a2SPeter Maydell 3194567663a2SPeter Maydell if (!fn) { 3195567663a2SPeter Maydell /* Bad size or size/q combination */ 3196567663a2SPeter Maydell return false; 3197567663a2SPeter Maydell } 3198567663a2SPeter Maydell 3199567663a2SPeter Maydell if (!vfp_access_check(s)) { 3200567663a2SPeter Maydell return true; 3201567663a2SPeter Maydell } 3202567663a2SPeter Maydell 3203567663a2SPeter Maydell pd = vfp_reg_ptr(true, a->vd); 3204567663a2SPeter Maydell pm = vfp_reg_ptr(true, a->vm); 3205567663a2SPeter Maydell fn(pd, pm); 3206567663a2SPeter Maydell tcg_temp_free_ptr(pd); 3207567663a2SPeter Maydell tcg_temp_free_ptr(pm); 3208567663a2SPeter Maydell return true; 3209567663a2SPeter Maydell } 3210567663a2SPeter Maydell 3211567663a2SPeter Maydell static bool trans_VUZP(DisasContext *s, arg_2misc *a) 3212567663a2SPeter Maydell { 3213567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3214567663a2SPeter Maydell { 3215567663a2SPeter Maydell gen_helper_neon_unzip8, 3216567663a2SPeter Maydell gen_helper_neon_unzip16, 3217567663a2SPeter Maydell NULL, 3218567663a2SPeter Maydell NULL, 3219567663a2SPeter Maydell }, { 3220567663a2SPeter Maydell gen_helper_neon_qunzip8, 3221567663a2SPeter Maydell gen_helper_neon_qunzip16, 3222567663a2SPeter Maydell gen_helper_neon_qunzip32, 3223567663a2SPeter Maydell NULL, 3224567663a2SPeter Maydell } 3225567663a2SPeter Maydell }; 3226567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3227567663a2SPeter Maydell } 3228567663a2SPeter Maydell 3229567663a2SPeter Maydell static bool trans_VZIP(DisasContext *s, arg_2misc *a) 3230567663a2SPeter Maydell { 3231567663a2SPeter Maydell static ZipFn * const fn[2][4] = { 3232567663a2SPeter Maydell { 3233567663a2SPeter Maydell gen_helper_neon_zip8, 3234567663a2SPeter Maydell gen_helper_neon_zip16, 3235567663a2SPeter Maydell NULL, 3236567663a2SPeter Maydell NULL, 3237567663a2SPeter Maydell }, { 3238567663a2SPeter Maydell gen_helper_neon_qzip8, 3239567663a2SPeter Maydell gen_helper_neon_qzip16, 3240567663a2SPeter Maydell gen_helper_neon_qzip32, 3241567663a2SPeter Maydell NULL, 3242567663a2SPeter Maydell } 3243567663a2SPeter Maydell }; 3244567663a2SPeter Maydell return do_zip_uzp(s, a, fn[a->q][a->size]); 3245567663a2SPeter Maydell } 32463882bdacSPeter Maydell 32473882bdacSPeter Maydell static bool do_vmovn(DisasContext *s, arg_2misc *a, 32483882bdacSPeter Maydell NeonGenNarrowEnvFn *narrowfn) 32493882bdacSPeter Maydell { 32503882bdacSPeter Maydell TCGv_i64 rm; 32513882bdacSPeter Maydell TCGv_i32 rd0, rd1; 32523882bdacSPeter Maydell 32533882bdacSPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 32543882bdacSPeter Maydell return false; 32553882bdacSPeter Maydell } 32563882bdacSPeter Maydell 32573882bdacSPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 32583882bdacSPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 32593882bdacSPeter Maydell ((a->vd | a->vm) & 0x10)) { 32603882bdacSPeter Maydell return false; 32613882bdacSPeter Maydell } 32623882bdacSPeter Maydell 32633882bdacSPeter Maydell if (a->vm & 1) { 32643882bdacSPeter Maydell return false; 32653882bdacSPeter Maydell } 32663882bdacSPeter Maydell 32673882bdacSPeter Maydell if (!narrowfn) { 32683882bdacSPeter Maydell return false; 32693882bdacSPeter Maydell } 32703882bdacSPeter Maydell 32713882bdacSPeter Maydell if (!vfp_access_check(s)) { 32723882bdacSPeter Maydell return true; 32733882bdacSPeter Maydell } 32743882bdacSPeter Maydell 32753882bdacSPeter Maydell rm = tcg_temp_new_i64(); 32763882bdacSPeter Maydell rd0 = tcg_temp_new_i32(); 32773882bdacSPeter Maydell rd1 = tcg_temp_new_i32(); 32783882bdacSPeter Maydell 32793882bdacSPeter Maydell neon_load_reg64(rm, a->vm); 32803882bdacSPeter Maydell narrowfn(rd0, cpu_env, rm); 32813882bdacSPeter Maydell neon_load_reg64(rm, a->vm + 1); 32823882bdacSPeter Maydell narrowfn(rd1, cpu_env, rm); 32833882bdacSPeter Maydell neon_store_reg(a->vd, 0, rd0); 32843882bdacSPeter Maydell neon_store_reg(a->vd, 1, rd1); 32853882bdacSPeter Maydell tcg_temp_free_i64(rm); 32863882bdacSPeter Maydell return true; 32873882bdacSPeter Maydell } 32883882bdacSPeter Maydell 32893882bdacSPeter Maydell #define DO_VMOVN(INSN, FUNC) \ 32903882bdacSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 32913882bdacSPeter Maydell { \ 32923882bdacSPeter Maydell static NeonGenNarrowEnvFn * const narrowfn[] = { \ 32933882bdacSPeter Maydell FUNC##8, \ 32943882bdacSPeter Maydell FUNC##16, \ 32953882bdacSPeter Maydell FUNC##32, \ 32963882bdacSPeter Maydell NULL, \ 32973882bdacSPeter Maydell }; \ 32983882bdacSPeter Maydell return do_vmovn(s, a, narrowfn[a->size]); \ 32993882bdacSPeter Maydell } 33003882bdacSPeter Maydell 33013882bdacSPeter Maydell DO_VMOVN(VMOVN, gen_neon_narrow_u) 33023882bdacSPeter Maydell DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) 33033882bdacSPeter Maydell DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) 33043882bdacSPeter Maydell DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) 3305749e2be3SPeter Maydell 3306749e2be3SPeter Maydell static bool trans_VSHLL(DisasContext *s, arg_2misc *a) 3307749e2be3SPeter Maydell { 3308749e2be3SPeter Maydell TCGv_i32 rm0, rm1; 3309749e2be3SPeter Maydell TCGv_i64 rd; 3310749e2be3SPeter Maydell static NeonGenWidenFn * const widenfns[] = { 3311749e2be3SPeter Maydell gen_helper_neon_widen_u8, 3312749e2be3SPeter Maydell gen_helper_neon_widen_u16, 3313749e2be3SPeter Maydell tcg_gen_extu_i32_i64, 3314749e2be3SPeter Maydell NULL, 3315749e2be3SPeter Maydell }; 3316749e2be3SPeter Maydell NeonGenWidenFn *widenfn = widenfns[a->size]; 3317749e2be3SPeter Maydell 3318749e2be3SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 3319749e2be3SPeter Maydell return false; 3320749e2be3SPeter Maydell } 3321749e2be3SPeter Maydell 3322749e2be3SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3323749e2be3SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3324749e2be3SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3325749e2be3SPeter Maydell return false; 3326749e2be3SPeter Maydell } 3327749e2be3SPeter Maydell 3328749e2be3SPeter Maydell if (a->vd & 1) { 3329749e2be3SPeter Maydell return false; 3330749e2be3SPeter Maydell } 3331749e2be3SPeter Maydell 3332749e2be3SPeter Maydell if (!widenfn) { 3333749e2be3SPeter Maydell return false; 3334749e2be3SPeter Maydell } 3335749e2be3SPeter Maydell 3336749e2be3SPeter Maydell if (!vfp_access_check(s)) { 3337749e2be3SPeter Maydell return true; 3338749e2be3SPeter Maydell } 3339749e2be3SPeter Maydell 3340749e2be3SPeter Maydell rd = tcg_temp_new_i64(); 3341749e2be3SPeter Maydell 3342749e2be3SPeter Maydell rm0 = neon_load_reg(a->vm, 0); 3343749e2be3SPeter Maydell rm1 = neon_load_reg(a->vm, 1); 3344749e2be3SPeter Maydell 3345749e2be3SPeter Maydell widenfn(rd, rm0); 3346749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 3347749e2be3SPeter Maydell neon_store_reg64(rd, a->vd); 3348749e2be3SPeter Maydell widenfn(rd, rm1); 3349749e2be3SPeter Maydell tcg_gen_shli_i64(rd, rd, 8 << a->size); 3350749e2be3SPeter Maydell neon_store_reg64(rd, a->vd + 1); 3351749e2be3SPeter Maydell 3352749e2be3SPeter Maydell tcg_temp_free_i64(rd); 3353749e2be3SPeter Maydell tcg_temp_free_i32(rm0); 3354749e2be3SPeter Maydell tcg_temp_free_i32(rm1); 3355749e2be3SPeter Maydell return true; 3356749e2be3SPeter Maydell } 3357654a5173SPeter Maydell 3358654a5173SPeter Maydell static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) 3359654a5173SPeter Maydell { 3360654a5173SPeter Maydell TCGv_ptr fpst; 3361654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3362654a5173SPeter Maydell 3363654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3364654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3365654a5173SPeter Maydell return false; 3366654a5173SPeter Maydell } 3367654a5173SPeter Maydell 3368654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3369654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3370654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3371654a5173SPeter Maydell return false; 3372654a5173SPeter Maydell } 3373654a5173SPeter Maydell 3374654a5173SPeter Maydell if ((a->vm & 1) || (a->size != 1)) { 3375654a5173SPeter Maydell return false; 3376654a5173SPeter Maydell } 3377654a5173SPeter Maydell 3378654a5173SPeter Maydell if (!vfp_access_check(s)) { 3379654a5173SPeter Maydell return true; 3380654a5173SPeter Maydell } 3381654a5173SPeter Maydell 3382654a5173SPeter Maydell fpst = get_fpstatus_ptr(true); 3383654a5173SPeter Maydell ahp = get_ahp_flag(); 3384654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 0); 3385654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3386654a5173SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 3387654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp); 3388654a5173SPeter Maydell tcg_gen_shli_i32(tmp2, tmp2, 16); 3389654a5173SPeter Maydell tcg_gen_or_i32(tmp2, tmp2, tmp); 3390654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3391654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 2); 3392654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); 3393654a5173SPeter Maydell tmp3 = neon_load_reg(a->vm, 3); 3394654a5173SPeter Maydell neon_store_reg(a->vd, 0, tmp2); 3395654a5173SPeter Maydell gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp); 3396654a5173SPeter Maydell tcg_gen_shli_i32(tmp3, tmp3, 16); 3397654a5173SPeter Maydell tcg_gen_or_i32(tmp3, tmp3, tmp); 3398654a5173SPeter Maydell neon_store_reg(a->vd, 1, tmp3); 3399654a5173SPeter Maydell tcg_temp_free_i32(tmp); 3400654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3401654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3402654a5173SPeter Maydell 3403654a5173SPeter Maydell return true; 3404654a5173SPeter Maydell } 3405654a5173SPeter Maydell 3406654a5173SPeter Maydell static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) 3407654a5173SPeter Maydell { 3408654a5173SPeter Maydell TCGv_ptr fpst; 3409654a5173SPeter Maydell TCGv_i32 ahp, tmp, tmp2, tmp3; 3410654a5173SPeter Maydell 3411654a5173SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON) || 3412654a5173SPeter Maydell !dc_isar_feature(aa32_fp16_spconv, s)) { 3413654a5173SPeter Maydell return false; 3414654a5173SPeter Maydell } 3415654a5173SPeter Maydell 3416654a5173SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 3417654a5173SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 3418654a5173SPeter Maydell ((a->vd | a->vm) & 0x10)) { 3419654a5173SPeter Maydell return false; 3420654a5173SPeter Maydell } 3421654a5173SPeter Maydell 3422654a5173SPeter Maydell if ((a->vd & 1) || (a->size != 1)) { 3423654a5173SPeter Maydell return false; 3424654a5173SPeter Maydell } 3425654a5173SPeter Maydell 3426654a5173SPeter Maydell if (!vfp_access_check(s)) { 3427654a5173SPeter Maydell return true; 3428654a5173SPeter Maydell } 3429654a5173SPeter Maydell 3430654a5173SPeter Maydell fpst = get_fpstatus_ptr(true); 3431654a5173SPeter Maydell ahp = get_ahp_flag(); 3432654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3433654a5173SPeter Maydell tmp = neon_load_reg(a->vm, 0); 3434654a5173SPeter Maydell tmp2 = neon_load_reg(a->vm, 1); 3435654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp); 3436654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3437654a5173SPeter Maydell neon_store_reg(a->vd, 0, tmp3); 3438654a5173SPeter Maydell tcg_gen_shri_i32(tmp, tmp, 16); 3439654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); 3440654a5173SPeter Maydell neon_store_reg(a->vd, 1, tmp); 3441654a5173SPeter Maydell tmp3 = tcg_temp_new_i32(); 3442654a5173SPeter Maydell tcg_gen_ext16u_i32(tmp3, tmp2); 3443654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); 3444654a5173SPeter Maydell neon_store_reg(a->vd, 2, tmp3); 3445654a5173SPeter Maydell tcg_gen_shri_i32(tmp2, tmp2, 16); 3446654a5173SPeter Maydell gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); 3447654a5173SPeter Maydell neon_store_reg(a->vd, 3, tmp2); 3448654a5173SPeter Maydell tcg_temp_free_i32(ahp); 3449654a5173SPeter Maydell tcg_temp_free_ptr(fpst); 3450654a5173SPeter Maydell 3451654a5173SPeter Maydell return true; 3452654a5173SPeter Maydell } 345375153179SPeter Maydell 345475153179SPeter Maydell static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) 345575153179SPeter Maydell { 345675153179SPeter Maydell int vec_size = a->q ? 16 : 8; 345775153179SPeter Maydell int rd_ofs = neon_reg_offset(a->vd, 0); 345875153179SPeter Maydell int rm_ofs = neon_reg_offset(a->vm, 0); 345975153179SPeter Maydell 346075153179SPeter Maydell if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { 346175153179SPeter Maydell return false; 346275153179SPeter Maydell } 346375153179SPeter Maydell 346475153179SPeter Maydell /* UNDEF accesses to D16-D31 if they don't exist. */ 346575153179SPeter Maydell if (!dc_isar_feature(aa32_simd_r32, s) && 346675153179SPeter Maydell ((a->vd | a->vm) & 0x10)) { 346775153179SPeter Maydell return false; 346875153179SPeter Maydell } 346975153179SPeter Maydell 347075153179SPeter Maydell if (a->size == 3) { 347175153179SPeter Maydell return false; 347275153179SPeter Maydell } 347375153179SPeter Maydell 347475153179SPeter Maydell if ((a->vd | a->vm) & a->q) { 347575153179SPeter Maydell return false; 347675153179SPeter Maydell } 347775153179SPeter Maydell 347875153179SPeter Maydell if (!vfp_access_check(s)) { 347975153179SPeter Maydell return true; 348075153179SPeter Maydell } 348175153179SPeter Maydell 348275153179SPeter Maydell fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); 348375153179SPeter Maydell 348475153179SPeter Maydell return true; 348575153179SPeter Maydell } 348675153179SPeter Maydell 348775153179SPeter Maydell #define DO_2MISC_VEC(INSN, FN) \ 348875153179SPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 348975153179SPeter Maydell { \ 349075153179SPeter Maydell return do_2misc_vec(s, a, FN); \ 349175153179SPeter Maydell } 349275153179SPeter Maydell 349375153179SPeter Maydell DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) 349475153179SPeter Maydell DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) 349575153179SPeter Maydell DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) 349675153179SPeter Maydell DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) 349775153179SPeter Maydell DO_2MISC_VEC(VCLE0, gen_gvec_cle0) 349875153179SPeter Maydell DO_2MISC_VEC(VCGE0, gen_gvec_cge0) 349975153179SPeter Maydell DO_2MISC_VEC(VCLT0, gen_gvec_clt0) 350075153179SPeter Maydell 350175153179SPeter Maydell static bool trans_VMVN(DisasContext *s, arg_2misc *a) 350275153179SPeter Maydell { 350375153179SPeter Maydell if (a->size != 0) { 350475153179SPeter Maydell return false; 350575153179SPeter Maydell } 350675153179SPeter Maydell return do_2misc_vec(s, a, tcg_gen_gvec_not); 350775153179SPeter Maydell } 35080b30dd5bSPeter Maydell 35090b30dd5bSPeter Maydell #define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ 35100b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35110b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35120b30dd5bSPeter Maydell uint32_t maxsz) \ 35130b30dd5bSPeter Maydell { \ 35140b30dd5bSPeter Maydell tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ 35150b30dd5bSPeter Maydell DATA, FUNC); \ 35160b30dd5bSPeter Maydell } 35170b30dd5bSPeter Maydell 35180b30dd5bSPeter Maydell #define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ 35190b30dd5bSPeter Maydell static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ 35200b30dd5bSPeter Maydell uint32_t rm_ofs, uint32_t oprsz, \ 35210b30dd5bSPeter Maydell uint32_t maxsz) \ 35220b30dd5bSPeter Maydell { \ 35230b30dd5bSPeter Maydell tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ 35240b30dd5bSPeter Maydell } 35250b30dd5bSPeter Maydell 35260b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) 35270b30dd5bSPeter Maydell WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) 35280b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) 35290b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) 35300b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) 35310b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) 35320b30dd5bSPeter Maydell WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) 35330b30dd5bSPeter Maydell 35340b30dd5bSPeter Maydell #define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ 35350b30dd5bSPeter Maydell static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ 35360b30dd5bSPeter Maydell { \ 35370b30dd5bSPeter Maydell if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ 35380b30dd5bSPeter Maydell return false; \ 35390b30dd5bSPeter Maydell } \ 35400b30dd5bSPeter Maydell return do_2misc_vec(s, a, gen_##INSN); \ 35410b30dd5bSPeter Maydell } 35420b30dd5bSPeter Maydell 35430b30dd5bSPeter Maydell DO_2M_CRYPTO(AESE, aa32_aes, 0) 35440b30dd5bSPeter Maydell DO_2M_CRYPTO(AESD, aa32_aes, 0) 35450b30dd5bSPeter Maydell DO_2M_CRYPTO(AESMC, aa32_aes, 0) 35460b30dd5bSPeter Maydell DO_2M_CRYPTO(AESIMC, aa32_aes, 0) 35470b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) 35480b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) 35490b30dd5bSPeter Maydell DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) 3550