xref: /qemu/target/arm/tcg/translate-neon.c (revision a27b46304352a0eced45e560e96515dbe3cc174f)
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 
29625e3dd4SPeter Maydell /* Include the generated Neon decoder */
30625e3dd4SPeter Maydell #include "decode-neon-dp.inc.c"
31625e3dd4SPeter Maydell #include "decode-neon-ls.inc.c"
32625e3dd4SPeter Maydell #include "decode-neon-shared.inc.c"
33afff8de0SPeter Maydell 
34afff8de0SPeter Maydell static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
35afff8de0SPeter Maydell {
36afff8de0SPeter Maydell     int opr_sz;
37afff8de0SPeter Maydell     TCGv_ptr fpst;
38afff8de0SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
39afff8de0SPeter Maydell 
40afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
41afff8de0SPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
42afff8de0SPeter Maydell         return false;
43afff8de0SPeter Maydell     }
44afff8de0SPeter Maydell 
45afff8de0SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
46afff8de0SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
47afff8de0SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
48afff8de0SPeter Maydell         return false;
49afff8de0SPeter Maydell     }
50afff8de0SPeter Maydell 
51afff8de0SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
52afff8de0SPeter Maydell         return false;
53afff8de0SPeter Maydell     }
54afff8de0SPeter Maydell 
55afff8de0SPeter Maydell     if (!vfp_access_check(s)) {
56afff8de0SPeter Maydell         return true;
57afff8de0SPeter Maydell     }
58afff8de0SPeter Maydell 
59afff8de0SPeter Maydell     opr_sz = (1 + a->q) * 8;
60afff8de0SPeter Maydell     fpst = get_fpstatus_ptr(1);
61afff8de0SPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcmlas : gen_helper_gvec_fcmlah;
62afff8de0SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
63afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vn),
64afff8de0SPeter Maydell                        vfp_reg_offset(1, a->vm),
65afff8de0SPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
66afff8de0SPeter Maydell                        fn_gvec_ptr);
67afff8de0SPeter Maydell     tcg_temp_free_ptr(fpst);
68afff8de0SPeter Maydell     return true;
69afff8de0SPeter Maydell }
7094d5eb7bSPeter Maydell 
7194d5eb7bSPeter Maydell static bool trans_VCADD(DisasContext *s, arg_VCADD *a)
7294d5eb7bSPeter Maydell {
7394d5eb7bSPeter Maydell     int opr_sz;
7494d5eb7bSPeter Maydell     TCGv_ptr fpst;
7594d5eb7bSPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
7694d5eb7bSPeter Maydell 
7794d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)
7894d5eb7bSPeter Maydell         || (!a->size && !dc_isar_feature(aa32_fp16_arith, s))) {
7994d5eb7bSPeter Maydell         return false;
8094d5eb7bSPeter Maydell     }
8194d5eb7bSPeter Maydell 
8294d5eb7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
8394d5eb7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
8494d5eb7bSPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
8594d5eb7bSPeter Maydell         return false;
8694d5eb7bSPeter Maydell     }
8794d5eb7bSPeter Maydell 
8894d5eb7bSPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
8994d5eb7bSPeter Maydell         return false;
9094d5eb7bSPeter Maydell     }
9194d5eb7bSPeter Maydell 
9294d5eb7bSPeter Maydell     if (!vfp_access_check(s)) {
9394d5eb7bSPeter Maydell         return true;
9494d5eb7bSPeter Maydell     }
9594d5eb7bSPeter Maydell 
9694d5eb7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
9794d5eb7bSPeter Maydell     fpst = get_fpstatus_ptr(1);
9894d5eb7bSPeter Maydell     fn_gvec_ptr = a->size ? gen_helper_gvec_fcadds : gen_helper_gvec_fcaddh;
9994d5eb7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
10094d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vn),
10194d5eb7bSPeter Maydell                        vfp_reg_offset(1, a->vm),
10294d5eb7bSPeter Maydell                        fpst, opr_sz, opr_sz, a->rot,
10394d5eb7bSPeter Maydell                        fn_gvec_ptr);
10494d5eb7bSPeter Maydell     tcg_temp_free_ptr(fpst);
10594d5eb7bSPeter Maydell     return true;
10694d5eb7bSPeter Maydell }
10732da0e33SPeter Maydell 
10832da0e33SPeter Maydell static bool trans_VDOT(DisasContext *s, arg_VDOT *a)
10932da0e33SPeter Maydell {
11032da0e33SPeter Maydell     int opr_sz;
11132da0e33SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
11232da0e33SPeter Maydell 
11332da0e33SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
11432da0e33SPeter Maydell         return false;
11532da0e33SPeter Maydell     }
11632da0e33SPeter Maydell 
11732da0e33SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
11832da0e33SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
11932da0e33SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
12032da0e33SPeter Maydell         return false;
12132da0e33SPeter Maydell     }
12232da0e33SPeter Maydell 
12332da0e33SPeter Maydell     if ((a->vn | a->vm | a->vd) & a->q) {
12432da0e33SPeter Maydell         return false;
12532da0e33SPeter Maydell     }
12632da0e33SPeter Maydell 
12732da0e33SPeter Maydell     if (!vfp_access_check(s)) {
12832da0e33SPeter Maydell         return true;
12932da0e33SPeter Maydell     }
13032da0e33SPeter Maydell 
13132da0e33SPeter Maydell     opr_sz = (1 + a->q) * 8;
13232da0e33SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
13332da0e33SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
13432da0e33SPeter Maydell                        vfp_reg_offset(1, a->vn),
13532da0e33SPeter Maydell                        vfp_reg_offset(1, a->vm),
13632da0e33SPeter Maydell                        opr_sz, opr_sz, 0, fn_gvec);
13732da0e33SPeter Maydell     return true;
13832da0e33SPeter Maydell }
1399a107e7bSPeter Maydell 
1409a107e7bSPeter Maydell static bool trans_VFML(DisasContext *s, arg_VFML *a)
1419a107e7bSPeter Maydell {
1429a107e7bSPeter Maydell     int opr_sz;
1439a107e7bSPeter Maydell 
1449a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
1459a107e7bSPeter Maydell         return false;
1469a107e7bSPeter Maydell     }
1479a107e7bSPeter Maydell 
1489a107e7bSPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1499a107e7bSPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1509a107e7bSPeter Maydell         (a->vd & 0x10)) {
1519a107e7bSPeter Maydell         return false;
1529a107e7bSPeter Maydell     }
1539a107e7bSPeter Maydell 
1549a107e7bSPeter Maydell     if (a->vd & a->q) {
1559a107e7bSPeter Maydell         return false;
1569a107e7bSPeter Maydell     }
1579a107e7bSPeter Maydell 
1589a107e7bSPeter Maydell     if (!vfp_access_check(s)) {
1599a107e7bSPeter Maydell         return true;
1609a107e7bSPeter Maydell     }
1619a107e7bSPeter Maydell 
1629a107e7bSPeter Maydell     opr_sz = (1 + a->q) * 8;
1639a107e7bSPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
1649a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vn),
1659a107e7bSPeter Maydell                        vfp_reg_offset(a->q, a->vm),
1669a107e7bSPeter Maydell                        cpu_env, opr_sz, opr_sz, a->s, /* is_2 == 0 */
1679a107e7bSPeter Maydell                        gen_helper_gvec_fmlal_a32);
1689a107e7bSPeter Maydell     return true;
1699a107e7bSPeter Maydell }
1707e1b5d61SPeter Maydell 
1717e1b5d61SPeter Maydell static bool trans_VCMLA_scalar(DisasContext *s, arg_VCMLA_scalar *a)
1727e1b5d61SPeter Maydell {
1737e1b5d61SPeter Maydell     gen_helper_gvec_3_ptr *fn_gvec_ptr;
1747e1b5d61SPeter Maydell     int opr_sz;
1757e1b5d61SPeter Maydell     TCGv_ptr fpst;
1767e1b5d61SPeter Maydell 
1777e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_vcma, s)) {
1787e1b5d61SPeter Maydell         return false;
1797e1b5d61SPeter Maydell     }
1807e1b5d61SPeter Maydell     if (a->size == 0 && !dc_isar_feature(aa32_fp16_arith, s)) {
1817e1b5d61SPeter Maydell         return false;
1827e1b5d61SPeter Maydell     }
1837e1b5d61SPeter Maydell 
1847e1b5d61SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
1857e1b5d61SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
1867e1b5d61SPeter Maydell         ((a->vd | a->vn | a->vm) & 0x10)) {
1877e1b5d61SPeter Maydell         return false;
1887e1b5d61SPeter Maydell     }
1897e1b5d61SPeter Maydell 
1907e1b5d61SPeter Maydell     if ((a->vd | a->vn) & a->q) {
1917e1b5d61SPeter Maydell         return false;
1927e1b5d61SPeter Maydell     }
1937e1b5d61SPeter Maydell 
1947e1b5d61SPeter Maydell     if (!vfp_access_check(s)) {
1957e1b5d61SPeter Maydell         return true;
1967e1b5d61SPeter Maydell     }
1977e1b5d61SPeter Maydell 
1987e1b5d61SPeter Maydell     fn_gvec_ptr = (a->size ? gen_helper_gvec_fcmlas_idx
1997e1b5d61SPeter Maydell                    : gen_helper_gvec_fcmlah_idx);
2007e1b5d61SPeter Maydell     opr_sz = (1 + a->q) * 8;
2017e1b5d61SPeter Maydell     fpst = get_fpstatus_ptr(1);
2027e1b5d61SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
2037e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vn),
2047e1b5d61SPeter Maydell                        vfp_reg_offset(1, a->vm),
2057e1b5d61SPeter Maydell                        fpst, opr_sz, opr_sz,
2067e1b5d61SPeter Maydell                        (a->index << 2) | a->rot, fn_gvec_ptr);
2077e1b5d61SPeter Maydell     tcg_temp_free_ptr(fpst);
2087e1b5d61SPeter Maydell     return true;
2097e1b5d61SPeter Maydell }
21035f5d4d1SPeter Maydell 
21135f5d4d1SPeter Maydell static bool trans_VDOT_scalar(DisasContext *s, arg_VDOT_scalar *a)
21235f5d4d1SPeter Maydell {
21335f5d4d1SPeter Maydell     gen_helper_gvec_3 *fn_gvec;
21435f5d4d1SPeter Maydell     int opr_sz;
21535f5d4d1SPeter Maydell     TCGv_ptr fpst;
21635f5d4d1SPeter Maydell 
21735f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_dp, s)) {
21835f5d4d1SPeter Maydell         return false;
21935f5d4d1SPeter Maydell     }
22035f5d4d1SPeter Maydell 
22135f5d4d1SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
22235f5d4d1SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
22335f5d4d1SPeter Maydell         ((a->vd | a->vn) & 0x10)) {
22435f5d4d1SPeter Maydell         return false;
22535f5d4d1SPeter Maydell     }
22635f5d4d1SPeter Maydell 
22735f5d4d1SPeter Maydell     if ((a->vd | a->vn) & a->q) {
22835f5d4d1SPeter Maydell         return false;
22935f5d4d1SPeter Maydell     }
23035f5d4d1SPeter Maydell 
23135f5d4d1SPeter Maydell     if (!vfp_access_check(s)) {
23235f5d4d1SPeter Maydell         return true;
23335f5d4d1SPeter Maydell     }
23435f5d4d1SPeter Maydell 
23535f5d4d1SPeter Maydell     fn_gvec = a->u ? gen_helper_gvec_udot_idx_b : gen_helper_gvec_sdot_idx_b;
23635f5d4d1SPeter Maydell     opr_sz = (1 + a->q) * 8;
23735f5d4d1SPeter Maydell     fpst = get_fpstatus_ptr(1);
23835f5d4d1SPeter Maydell     tcg_gen_gvec_3_ool(vfp_reg_offset(1, a->vd),
23935f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->vn),
24035f5d4d1SPeter Maydell                        vfp_reg_offset(1, a->rm),
24135f5d4d1SPeter Maydell                        opr_sz, opr_sz, a->index, fn_gvec);
24235f5d4d1SPeter Maydell     tcg_temp_free_ptr(fpst);
24335f5d4d1SPeter Maydell     return true;
24435f5d4d1SPeter Maydell }
245d27e82f7SPeter Maydell 
246d27e82f7SPeter Maydell static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
247d27e82f7SPeter Maydell {
248d27e82f7SPeter Maydell     int opr_sz;
249d27e82f7SPeter Maydell 
250d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_fhm, s)) {
251d27e82f7SPeter Maydell         return false;
252d27e82f7SPeter Maydell     }
253d27e82f7SPeter Maydell 
254d27e82f7SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist. */
255d27e82f7SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) &&
256d27e82f7SPeter Maydell         ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) {
257d27e82f7SPeter Maydell         return false;
258d27e82f7SPeter Maydell     }
259d27e82f7SPeter Maydell 
260d27e82f7SPeter Maydell     if (a->vd & a->q) {
261d27e82f7SPeter Maydell         return false;
262d27e82f7SPeter Maydell     }
263d27e82f7SPeter Maydell 
264d27e82f7SPeter Maydell     if (!vfp_access_check(s)) {
265d27e82f7SPeter Maydell         return true;
266d27e82f7SPeter Maydell     }
267d27e82f7SPeter Maydell 
268d27e82f7SPeter Maydell     opr_sz = (1 + a->q) * 8;
269d27e82f7SPeter Maydell     tcg_gen_gvec_3_ptr(vfp_reg_offset(1, a->vd),
270d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->vn),
271d27e82f7SPeter Maydell                        vfp_reg_offset(a->q, a->rm),
272d27e82f7SPeter Maydell                        cpu_env, opr_sz, opr_sz,
273d27e82f7SPeter Maydell                        (a->index << 2) | a->s, /* is_2 == 0 */
274d27e82f7SPeter Maydell                        gen_helper_gvec_fmlal_idx_a32);
275d27e82f7SPeter Maydell     return true;
276d27e82f7SPeter Maydell }
277a27b4630SPeter Maydell 
278a27b4630SPeter Maydell static struct {
279a27b4630SPeter Maydell     int nregs;
280a27b4630SPeter Maydell     int interleave;
281a27b4630SPeter Maydell     int spacing;
282a27b4630SPeter Maydell } const neon_ls_element_type[11] = {
283a27b4630SPeter Maydell     {1, 4, 1},
284a27b4630SPeter Maydell     {1, 4, 2},
285a27b4630SPeter Maydell     {4, 1, 1},
286a27b4630SPeter Maydell     {2, 2, 2},
287a27b4630SPeter Maydell     {1, 3, 1},
288a27b4630SPeter Maydell     {1, 3, 2},
289a27b4630SPeter Maydell     {3, 1, 1},
290a27b4630SPeter Maydell     {1, 1, 1},
291a27b4630SPeter Maydell     {1, 2, 1},
292a27b4630SPeter Maydell     {1, 2, 2},
293a27b4630SPeter Maydell     {2, 1, 1}
294a27b4630SPeter Maydell };
295a27b4630SPeter Maydell 
296a27b4630SPeter Maydell static void gen_neon_ldst_base_update(DisasContext *s, int rm, int rn,
297a27b4630SPeter Maydell                                       int stride)
298a27b4630SPeter Maydell {
299a27b4630SPeter Maydell     if (rm != 15) {
300a27b4630SPeter Maydell         TCGv_i32 base;
301a27b4630SPeter Maydell 
302a27b4630SPeter Maydell         base = load_reg(s, rn);
303a27b4630SPeter Maydell         if (rm == 13) {
304a27b4630SPeter Maydell             tcg_gen_addi_i32(base, base, stride);
305a27b4630SPeter Maydell         } else {
306a27b4630SPeter Maydell             TCGv_i32 index;
307a27b4630SPeter Maydell             index = load_reg(s, rm);
308a27b4630SPeter Maydell             tcg_gen_add_i32(base, base, index);
309a27b4630SPeter Maydell             tcg_temp_free_i32(index);
310a27b4630SPeter Maydell         }
311a27b4630SPeter Maydell         store_reg(s, rn, base);
312a27b4630SPeter Maydell     }
313a27b4630SPeter Maydell }
314a27b4630SPeter Maydell 
315a27b4630SPeter Maydell static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a)
316a27b4630SPeter Maydell {
317a27b4630SPeter Maydell     /* Neon load/store multiple structures */
318a27b4630SPeter Maydell     int nregs, interleave, spacing, reg, n;
319a27b4630SPeter Maydell     MemOp endian = s->be_data;
320a27b4630SPeter Maydell     int mmu_idx = get_mem_index(s);
321a27b4630SPeter Maydell     int size = a->size;
322a27b4630SPeter Maydell     TCGv_i64 tmp64;
323a27b4630SPeter Maydell     TCGv_i32 addr, tmp;
324a27b4630SPeter Maydell 
325a27b4630SPeter Maydell     if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
326a27b4630SPeter Maydell         return false;
327a27b4630SPeter Maydell     }
328a27b4630SPeter Maydell 
329a27b4630SPeter Maydell     /* UNDEF accesses to D16-D31 if they don't exist */
330a27b4630SPeter Maydell     if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
331a27b4630SPeter Maydell         return false;
332a27b4630SPeter Maydell     }
333a27b4630SPeter Maydell     if (a->itype > 10) {
334a27b4630SPeter Maydell         return false;
335a27b4630SPeter Maydell     }
336a27b4630SPeter Maydell     /* Catch UNDEF cases for bad values of align field */
337a27b4630SPeter Maydell     switch (a->itype & 0xc) {
338a27b4630SPeter Maydell     case 4:
339a27b4630SPeter Maydell         if (a->align >= 2) {
340a27b4630SPeter Maydell             return false;
341a27b4630SPeter Maydell         }
342a27b4630SPeter Maydell         break;
343a27b4630SPeter Maydell     case 8:
344a27b4630SPeter Maydell         if (a->align == 3) {
345a27b4630SPeter Maydell             return false;
346a27b4630SPeter Maydell         }
347a27b4630SPeter Maydell         break;
348a27b4630SPeter Maydell     default:
349a27b4630SPeter Maydell         break;
350a27b4630SPeter Maydell     }
351a27b4630SPeter Maydell     nregs = neon_ls_element_type[a->itype].nregs;
352a27b4630SPeter Maydell     interleave = neon_ls_element_type[a->itype].interleave;
353a27b4630SPeter Maydell     spacing = neon_ls_element_type[a->itype].spacing;
354a27b4630SPeter Maydell     if (size == 3 && (interleave | spacing) != 1) {
355a27b4630SPeter Maydell         return false;
356a27b4630SPeter Maydell     }
357a27b4630SPeter Maydell 
358a27b4630SPeter Maydell     if (!vfp_access_check(s)) {
359a27b4630SPeter Maydell         return true;
360a27b4630SPeter Maydell     }
361a27b4630SPeter Maydell 
362a27b4630SPeter Maydell     /* For our purposes, bytes are always little-endian.  */
363a27b4630SPeter Maydell     if (size == 0) {
364a27b4630SPeter Maydell         endian = MO_LE;
365a27b4630SPeter Maydell     }
366a27b4630SPeter Maydell     /*
367a27b4630SPeter Maydell      * Consecutive little-endian elements from a single register
368a27b4630SPeter Maydell      * can be promoted to a larger little-endian operation.
369a27b4630SPeter Maydell      */
370a27b4630SPeter Maydell     if (interleave == 1 && endian == MO_LE) {
371a27b4630SPeter Maydell         size = 3;
372a27b4630SPeter Maydell     }
373a27b4630SPeter Maydell     tmp64 = tcg_temp_new_i64();
374a27b4630SPeter Maydell     addr = tcg_temp_new_i32();
375a27b4630SPeter Maydell     tmp = tcg_const_i32(1 << size);
376a27b4630SPeter Maydell     load_reg_var(s, addr, a->rn);
377a27b4630SPeter Maydell     for (reg = 0; reg < nregs; reg++) {
378a27b4630SPeter Maydell         for (n = 0; n < 8 >> size; n++) {
379a27b4630SPeter Maydell             int xs;
380a27b4630SPeter Maydell             for (xs = 0; xs < interleave; xs++) {
381a27b4630SPeter Maydell                 int tt = a->vd + reg + spacing * xs;
382a27b4630SPeter Maydell 
383a27b4630SPeter Maydell                 if (a->l) {
384a27b4630SPeter Maydell                     gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size);
385a27b4630SPeter Maydell                     neon_store_element64(tt, n, size, tmp64);
386a27b4630SPeter Maydell                 } else {
387a27b4630SPeter Maydell                     neon_load_element64(tmp64, tt, n, size);
388a27b4630SPeter Maydell                     gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size);
389a27b4630SPeter Maydell                 }
390a27b4630SPeter Maydell                 tcg_gen_add_i32(addr, addr, tmp);
391a27b4630SPeter Maydell             }
392a27b4630SPeter Maydell         }
393a27b4630SPeter Maydell     }
394a27b4630SPeter Maydell     tcg_temp_free_i32(addr);
395a27b4630SPeter Maydell     tcg_temp_free_i32(tmp);
396a27b4630SPeter Maydell     tcg_temp_free_i64(tmp64);
397a27b4630SPeter Maydell 
398a27b4630SPeter Maydell     gen_neon_ldst_base_update(s, a->rm, a->rn, nregs * interleave * 8);
399a27b4630SPeter Maydell     return true;
400a27b4630SPeter Maydell }
401