xref: /qemu/target/arm/tcg/translate-sme.c (revision 558e956c71929f3ed2d571ff14ea067b5655bd24)
1e67cd1caSRichard Henderson /*
2e67cd1caSRichard Henderson  * AArch64 SME translation
3e67cd1caSRichard Henderson  *
4e67cd1caSRichard Henderson  * Copyright (c) 2022 Linaro, Ltd
5e67cd1caSRichard Henderson  *
6e67cd1caSRichard Henderson  * This library is free software; you can redistribute it and/or
7e67cd1caSRichard Henderson  * modify it under the terms of the GNU Lesser General Public
8e67cd1caSRichard Henderson  * License as published by the Free Software Foundation; either
9e67cd1caSRichard Henderson  * version 2.1 of the License, or (at your option) any later version.
10e67cd1caSRichard Henderson  *
11e67cd1caSRichard Henderson  * This library is distributed in the hope that it will be useful,
12e67cd1caSRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e67cd1caSRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e67cd1caSRichard Henderson  * Lesser General Public License for more details.
15e67cd1caSRichard Henderson  *
16e67cd1caSRichard Henderson  * You should have received a copy of the GNU Lesser General Public
17e67cd1caSRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18e67cd1caSRichard Henderson  */
19e67cd1caSRichard Henderson 
20e67cd1caSRichard Henderson #include "qemu/osdep.h"
21e67cd1caSRichard Henderson #include "cpu.h"
22e67cd1caSRichard Henderson #include "tcg/tcg-op.h"
23e67cd1caSRichard Henderson #include "tcg/tcg-op-gvec.h"
24e67cd1caSRichard Henderson #include "tcg/tcg-gvec-desc.h"
25e67cd1caSRichard Henderson #include "translate.h"
26e67cd1caSRichard Henderson #include "exec/helper-gen.h"
27e67cd1caSRichard Henderson #include "translate-a64.h"
28e67cd1caSRichard Henderson #include "fpu/softfloat.h"
29e67cd1caSRichard Henderson 
30e67cd1caSRichard Henderson 
31e67cd1caSRichard Henderson /*
32e67cd1caSRichard Henderson  * Include the generated decoder.
33e67cd1caSRichard Henderson  */
34e67cd1caSRichard Henderson 
35e67cd1caSRichard Henderson #include "decode-sme.c.inc"
36ad939afbSRichard Henderson 
37ad939afbSRichard Henderson 
38e9ad3ef1SRichard Henderson /*
39e9ad3ef1SRichard Henderson  * Resolve tile.size[index] to a host pointer, where tile and index
40e9ad3ef1SRichard Henderson  * are always decoded together, dependent on the element size.
41e9ad3ef1SRichard Henderson  */
42e9ad3ef1SRichard Henderson static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs,
43e9ad3ef1SRichard Henderson                                 int tile_index, bool vertical)
44e9ad3ef1SRichard Henderson {
45e9ad3ef1SRichard Henderson     int tile = tile_index >> (4 - esz);
46e9ad3ef1SRichard Henderson     int index = esz == MO_128 ? 0 : extract32(tile_index, 0, 4 - esz);
47e9ad3ef1SRichard Henderson     int pos, len, offset;
48e9ad3ef1SRichard Henderson     TCGv_i32 tmp;
49e9ad3ef1SRichard Henderson     TCGv_ptr addr;
50e9ad3ef1SRichard Henderson 
51e9ad3ef1SRichard Henderson     /* Compute the final index, which is Rs+imm. */
52e9ad3ef1SRichard Henderson     tmp = tcg_temp_new_i32();
53e9ad3ef1SRichard Henderson     tcg_gen_trunc_tl_i32(tmp, cpu_reg(s, rs));
54e9ad3ef1SRichard Henderson     tcg_gen_addi_i32(tmp, tmp, index);
55e9ad3ef1SRichard Henderson 
56e9ad3ef1SRichard Henderson     /* Prepare a power-of-two modulo via extraction of @len bits. */
57e9ad3ef1SRichard Henderson     len = ctz32(streaming_vec_reg_size(s)) - esz;
58e9ad3ef1SRichard Henderson 
59e9ad3ef1SRichard Henderson     if (vertical) {
60e9ad3ef1SRichard Henderson         /*
61e9ad3ef1SRichard Henderson          * Compute the byte offset of the index within the tile:
62e9ad3ef1SRichard Henderson          *     (index % (svl / size)) * size
63e9ad3ef1SRichard Henderson          *   = (index % (svl >> esz)) << esz
64e9ad3ef1SRichard Henderson          * Perform the power-of-two modulo via extraction of the low @len bits.
65e9ad3ef1SRichard Henderson          * Perform the multiply by shifting left by @pos bits.
66e9ad3ef1SRichard Henderson          * Perform these operations simultaneously via deposit into zero.
67e9ad3ef1SRichard Henderson          */
68e9ad3ef1SRichard Henderson         pos = esz;
69e9ad3ef1SRichard Henderson         tcg_gen_deposit_z_i32(tmp, tmp, pos, len);
70e9ad3ef1SRichard Henderson 
71e9ad3ef1SRichard Henderson         /*
72e9ad3ef1SRichard Henderson          * For big-endian, adjust the indexed column byte offset within
73e9ad3ef1SRichard Henderson          * the uint64_t host words that make up env->zarray[].
74e9ad3ef1SRichard Henderson          */
75e9ad3ef1SRichard Henderson         if (HOST_BIG_ENDIAN && esz < MO_64) {
76e9ad3ef1SRichard Henderson             tcg_gen_xori_i32(tmp, tmp, 8 - (1 << esz));
77e9ad3ef1SRichard Henderson         }
78e9ad3ef1SRichard Henderson     } else {
79e9ad3ef1SRichard Henderson         /*
80e9ad3ef1SRichard Henderson          * Compute the byte offset of the index within the tile:
81e9ad3ef1SRichard Henderson          *     (index % (svl / size)) * (size * sizeof(row))
82e9ad3ef1SRichard Henderson          *   = (index % (svl >> esz)) << (esz + log2(sizeof(row)))
83e9ad3ef1SRichard Henderson          */
84e9ad3ef1SRichard Henderson         pos = esz + ctz32(sizeof(ARMVectorReg));
85e9ad3ef1SRichard Henderson         tcg_gen_deposit_z_i32(tmp, tmp, pos, len);
86e9ad3ef1SRichard Henderson 
87e9ad3ef1SRichard Henderson         /* Row slices are always aligned and need no endian adjustment. */
88e9ad3ef1SRichard Henderson     }
89e9ad3ef1SRichard Henderson 
90e9ad3ef1SRichard Henderson     /* The tile byte offset within env->zarray is the row. */
91e9ad3ef1SRichard Henderson     offset = tile * sizeof(ARMVectorReg);
92e9ad3ef1SRichard Henderson 
93e9ad3ef1SRichard Henderson     /* Include the byte offset of zarray to make this relative to env. */
94e9ad3ef1SRichard Henderson     offset += offsetof(CPUARMState, zarray);
95e9ad3ef1SRichard Henderson     tcg_gen_addi_i32(tmp, tmp, offset);
96e9ad3ef1SRichard Henderson 
97e9ad3ef1SRichard Henderson     /* Add the byte offset to env to produce the final pointer. */
98e9ad3ef1SRichard Henderson     addr = tcg_temp_new_ptr();
99e9ad3ef1SRichard Henderson     tcg_gen_ext_i32_ptr(addr, tmp);
100e9ad3ef1SRichard Henderson     tcg_temp_free_i32(tmp);
101e9ad3ef1SRichard Henderson     tcg_gen_add_ptr(addr, addr, cpu_env);
102e9ad3ef1SRichard Henderson 
103e9ad3ef1SRichard Henderson     return addr;
104e9ad3ef1SRichard Henderson }
105e9ad3ef1SRichard Henderson 
106ad939afbSRichard Henderson static bool trans_ZERO(DisasContext *s, arg_ZERO *a)
107ad939afbSRichard Henderson {
108ad939afbSRichard Henderson     if (!dc_isar_feature(aa64_sme, s)) {
109ad939afbSRichard Henderson         return false;
110ad939afbSRichard Henderson     }
111ad939afbSRichard Henderson     if (sme_za_enabled_check(s)) {
112ad939afbSRichard Henderson         gen_helper_sme_zero(cpu_env, tcg_constant_i32(a->imm),
113ad939afbSRichard Henderson                             tcg_constant_i32(streaming_vec_reg_size(s)));
114ad939afbSRichard Henderson     }
115ad939afbSRichard Henderson     return true;
116ad939afbSRichard Henderson }
117e9ad3ef1SRichard Henderson 
118e9ad3ef1SRichard Henderson static bool trans_MOVA(DisasContext *s, arg_MOVA *a)
119e9ad3ef1SRichard Henderson {
120e9ad3ef1SRichard Henderson     static gen_helper_gvec_4 * const h_fns[5] = {
121e9ad3ef1SRichard Henderson         gen_helper_sve_sel_zpzz_b, gen_helper_sve_sel_zpzz_h,
122e9ad3ef1SRichard Henderson         gen_helper_sve_sel_zpzz_s, gen_helper_sve_sel_zpzz_d,
123e9ad3ef1SRichard Henderson         gen_helper_sve_sel_zpzz_q
124e9ad3ef1SRichard Henderson     };
125e9ad3ef1SRichard Henderson     static gen_helper_gvec_3 * const cz_fns[5] = {
126e9ad3ef1SRichard Henderson         gen_helper_sme_mova_cz_b, gen_helper_sme_mova_cz_h,
127e9ad3ef1SRichard Henderson         gen_helper_sme_mova_cz_s, gen_helper_sme_mova_cz_d,
128e9ad3ef1SRichard Henderson         gen_helper_sme_mova_cz_q,
129e9ad3ef1SRichard Henderson     };
130e9ad3ef1SRichard Henderson     static gen_helper_gvec_3 * const zc_fns[5] = {
131e9ad3ef1SRichard Henderson         gen_helper_sme_mova_zc_b, gen_helper_sme_mova_zc_h,
132e9ad3ef1SRichard Henderson         gen_helper_sme_mova_zc_s, gen_helper_sme_mova_zc_d,
133e9ad3ef1SRichard Henderson         gen_helper_sme_mova_zc_q,
134e9ad3ef1SRichard Henderson     };
135e9ad3ef1SRichard Henderson 
136e9ad3ef1SRichard Henderson     TCGv_ptr t_za, t_zr, t_pg;
137e9ad3ef1SRichard Henderson     TCGv_i32 t_desc;
138e9ad3ef1SRichard Henderson     int svl;
139e9ad3ef1SRichard Henderson 
140e9ad3ef1SRichard Henderson     if (!dc_isar_feature(aa64_sme, s)) {
141e9ad3ef1SRichard Henderson         return false;
142e9ad3ef1SRichard Henderson     }
143e9ad3ef1SRichard Henderson     if (!sme_smza_enabled_check(s)) {
144e9ad3ef1SRichard Henderson         return true;
145e9ad3ef1SRichard Henderson     }
146e9ad3ef1SRichard Henderson 
147e9ad3ef1SRichard Henderson     t_za = get_tile_rowcol(s, a->esz, a->rs, a->za_imm, a->v);
148e9ad3ef1SRichard Henderson     t_zr = vec_full_reg_ptr(s, a->zr);
149e9ad3ef1SRichard Henderson     t_pg = pred_full_reg_ptr(s, a->pg);
150e9ad3ef1SRichard Henderson 
151e9ad3ef1SRichard Henderson     svl = streaming_vec_reg_size(s);
152e9ad3ef1SRichard Henderson     t_desc = tcg_constant_i32(simd_desc(svl, svl, 0));
153e9ad3ef1SRichard Henderson 
154e9ad3ef1SRichard Henderson     if (a->v) {
155e9ad3ef1SRichard Henderson         /* Vertical slice -- use sme mova helpers. */
156e9ad3ef1SRichard Henderson         if (a->to_vec) {
157e9ad3ef1SRichard Henderson             zc_fns[a->esz](t_zr, t_za, t_pg, t_desc);
158e9ad3ef1SRichard Henderson         } else {
159e9ad3ef1SRichard Henderson             cz_fns[a->esz](t_za, t_zr, t_pg, t_desc);
160e9ad3ef1SRichard Henderson         }
161e9ad3ef1SRichard Henderson     } else {
162e9ad3ef1SRichard Henderson         /* Horizontal slice -- reuse sve sel helpers. */
163e9ad3ef1SRichard Henderson         if (a->to_vec) {
164e9ad3ef1SRichard Henderson             h_fns[a->esz](t_zr, t_za, t_zr, t_pg, t_desc);
165e9ad3ef1SRichard Henderson         } else {
166e9ad3ef1SRichard Henderson             h_fns[a->esz](t_za, t_zr, t_za, t_pg, t_desc);
167e9ad3ef1SRichard Henderson         }
168e9ad3ef1SRichard Henderson     }
169e9ad3ef1SRichard Henderson 
170e9ad3ef1SRichard Henderson     tcg_temp_free_ptr(t_za);
171e9ad3ef1SRichard Henderson     tcg_temp_free_ptr(t_zr);
172e9ad3ef1SRichard Henderson     tcg_temp_free_ptr(t_pg);
173e9ad3ef1SRichard Henderson 
174e9ad3ef1SRichard Henderson     return true;
175e9ad3ef1SRichard Henderson }
1767390e0e9SRichard Henderson 
1777390e0e9SRichard Henderson static bool trans_LDST1(DisasContext *s, arg_LDST1 *a)
1787390e0e9SRichard Henderson {
1797390e0e9SRichard Henderson     typedef void GenLdSt1(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv, TCGv_i32);
1807390e0e9SRichard Henderson 
1817390e0e9SRichard Henderson     /*
1827390e0e9SRichard Henderson      * Indexed by [esz][be][v][mte][st], which is (except for load/store)
1837390e0e9SRichard Henderson      * also the order in which the elements appear in the function names,
1847390e0e9SRichard Henderson      * and so how we must concatenate the pieces.
1857390e0e9SRichard Henderson      */
1867390e0e9SRichard Henderson 
1877390e0e9SRichard Henderson #define FN_LS(F)     { gen_helper_sme_ld1##F, gen_helper_sme_st1##F }
1887390e0e9SRichard Henderson #define FN_MTE(F)    { FN_LS(F), FN_LS(F##_mte) }
1897390e0e9SRichard Henderson #define FN_HV(F)     { FN_MTE(F##_h), FN_MTE(F##_v) }
1907390e0e9SRichard Henderson #define FN_END(L, B) { FN_HV(L), FN_HV(B) }
1917390e0e9SRichard Henderson 
1927390e0e9SRichard Henderson     static GenLdSt1 * const fns[5][2][2][2][2] = {
1937390e0e9SRichard Henderson         FN_END(b, b),
1947390e0e9SRichard Henderson         FN_END(h_le, h_be),
1957390e0e9SRichard Henderson         FN_END(s_le, s_be),
1967390e0e9SRichard Henderson         FN_END(d_le, d_be),
1977390e0e9SRichard Henderson         FN_END(q_le, q_be),
1987390e0e9SRichard Henderson     };
1997390e0e9SRichard Henderson 
2007390e0e9SRichard Henderson #undef FN_LS
2017390e0e9SRichard Henderson #undef FN_MTE
2027390e0e9SRichard Henderson #undef FN_HV
2037390e0e9SRichard Henderson #undef FN_END
2047390e0e9SRichard Henderson 
2057390e0e9SRichard Henderson     TCGv_ptr t_za, t_pg;
2067390e0e9SRichard Henderson     TCGv_i64 addr;
2077390e0e9SRichard Henderson     int svl, desc = 0;
2087390e0e9SRichard Henderson     bool be = s->be_data == MO_BE;
2097390e0e9SRichard Henderson     bool mte = s->mte_active[0];
2107390e0e9SRichard Henderson 
2117390e0e9SRichard Henderson     if (!dc_isar_feature(aa64_sme, s)) {
2127390e0e9SRichard Henderson         return false;
2137390e0e9SRichard Henderson     }
2147390e0e9SRichard Henderson     if (!sme_smza_enabled_check(s)) {
2157390e0e9SRichard Henderson         return true;
2167390e0e9SRichard Henderson     }
2177390e0e9SRichard Henderson 
2187390e0e9SRichard Henderson     t_za = get_tile_rowcol(s, a->esz, a->rs, a->za_imm, a->v);
2197390e0e9SRichard Henderson     t_pg = pred_full_reg_ptr(s, a->pg);
2207390e0e9SRichard Henderson     addr = tcg_temp_new_i64();
2217390e0e9SRichard Henderson 
2227390e0e9SRichard Henderson     tcg_gen_shli_i64(addr, cpu_reg(s, a->rm), a->esz);
2237390e0e9SRichard Henderson     tcg_gen_add_i64(addr, addr, cpu_reg_sp(s, a->rn));
2247390e0e9SRichard Henderson 
2257390e0e9SRichard Henderson     if (mte) {
2267390e0e9SRichard Henderson         desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s));
2277390e0e9SRichard Henderson         desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
2287390e0e9SRichard Henderson         desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
2297390e0e9SRichard Henderson         desc = FIELD_DP32(desc, MTEDESC, WRITE, a->st);
2307390e0e9SRichard Henderson         desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << a->esz) - 1);
2317390e0e9SRichard Henderson         desc <<= SVE_MTEDESC_SHIFT;
2327390e0e9SRichard Henderson     } else {
2337390e0e9SRichard Henderson         addr = clean_data_tbi(s, addr);
2347390e0e9SRichard Henderson     }
2357390e0e9SRichard Henderson     svl = streaming_vec_reg_size(s);
2367390e0e9SRichard Henderson     desc = simd_desc(svl, svl, desc);
2377390e0e9SRichard Henderson 
2387390e0e9SRichard Henderson     fns[a->esz][be][a->v][mte][a->st](cpu_env, t_za, t_pg, addr,
2397390e0e9SRichard Henderson                                       tcg_constant_i32(desc));
2407390e0e9SRichard Henderson 
2417390e0e9SRichard Henderson     tcg_temp_free_ptr(t_za);
2427390e0e9SRichard Henderson     tcg_temp_free_ptr(t_pg);
2437390e0e9SRichard Henderson     tcg_temp_free_i64(addr);
2447390e0e9SRichard Henderson     return true;
2457390e0e9SRichard Henderson }
2464c46a5f1SRichard Henderson 
2474c46a5f1SRichard Henderson typedef void GenLdStR(DisasContext *, TCGv_ptr, int, int, int, int);
2484c46a5f1SRichard Henderson 
2494c46a5f1SRichard Henderson static bool do_ldst_r(DisasContext *s, arg_ldstr *a, GenLdStR *fn)
2504c46a5f1SRichard Henderson {
2514c46a5f1SRichard Henderson     int svl = streaming_vec_reg_size(s);
2524c46a5f1SRichard Henderson     int imm = a->imm;
2534c46a5f1SRichard Henderson     TCGv_ptr base;
2544c46a5f1SRichard Henderson 
2554c46a5f1SRichard Henderson     if (!sme_za_enabled_check(s)) {
2564c46a5f1SRichard Henderson         return true;
2574c46a5f1SRichard Henderson     }
2584c46a5f1SRichard Henderson 
2594c46a5f1SRichard Henderson     /* ZA[n] equates to ZA0H.B[n]. */
2604c46a5f1SRichard Henderson     base = get_tile_rowcol(s, MO_8, a->rv, imm, false);
2614c46a5f1SRichard Henderson 
2624c46a5f1SRichard Henderson     fn(s, base, 0, svl, a->rn, imm * svl);
2634c46a5f1SRichard Henderson 
2644c46a5f1SRichard Henderson     tcg_temp_free_ptr(base);
2654c46a5f1SRichard Henderson     return true;
2664c46a5f1SRichard Henderson }
2674c46a5f1SRichard Henderson 
2684c46a5f1SRichard Henderson TRANS_FEAT(LDR, aa64_sme, do_ldst_r, a, gen_sve_ldr)
2694c46a5f1SRichard Henderson TRANS_FEAT(STR, aa64_sme, do_ldst_r, a, gen_sve_str)
270bc4420d9SRichard Henderson 
271bc4420d9SRichard Henderson static bool do_adda(DisasContext *s, arg_adda *a, MemOp esz,
272bc4420d9SRichard Henderson                     gen_helper_gvec_4 *fn)
273bc4420d9SRichard Henderson {
274bc4420d9SRichard Henderson     int svl = streaming_vec_reg_size(s);
275bc4420d9SRichard Henderson     uint32_t desc = simd_desc(svl, svl, 0);
276bc4420d9SRichard Henderson     TCGv_ptr za, zn, pn, pm;
277bc4420d9SRichard Henderson 
278bc4420d9SRichard Henderson     if (!sme_smza_enabled_check(s)) {
279bc4420d9SRichard Henderson         return true;
280bc4420d9SRichard Henderson     }
281bc4420d9SRichard Henderson 
282bc4420d9SRichard Henderson     /* Sum XZR+zad to find ZAd. */
283bc4420d9SRichard Henderson     za = get_tile_rowcol(s, esz, 31, a->zad, false);
284bc4420d9SRichard Henderson     zn = vec_full_reg_ptr(s, a->zn);
285bc4420d9SRichard Henderson     pn = pred_full_reg_ptr(s, a->pn);
286bc4420d9SRichard Henderson     pm = pred_full_reg_ptr(s, a->pm);
287bc4420d9SRichard Henderson 
288bc4420d9SRichard Henderson     fn(za, zn, pn, pm, tcg_constant_i32(desc));
289bc4420d9SRichard Henderson 
290bc4420d9SRichard Henderson     tcg_temp_free_ptr(za);
291bc4420d9SRichard Henderson     tcg_temp_free_ptr(zn);
292bc4420d9SRichard Henderson     tcg_temp_free_ptr(pn);
293bc4420d9SRichard Henderson     tcg_temp_free_ptr(pm);
294bc4420d9SRichard Henderson     return true;
295bc4420d9SRichard Henderson }
296bc4420d9SRichard Henderson 
297bc4420d9SRichard Henderson TRANS_FEAT(ADDHA_s, aa64_sme, do_adda, a, MO_32, gen_helper_sme_addha_s)
298bc4420d9SRichard Henderson TRANS_FEAT(ADDVA_s, aa64_sme, do_adda, a, MO_32, gen_helper_sme_addva_s)
299bc4420d9SRichard Henderson TRANS_FEAT(ADDHA_d, aa64_sme_i16i64, do_adda, a, MO_64, gen_helper_sme_addha_d)
300bc4420d9SRichard Henderson TRANS_FEAT(ADDVA_d, aa64_sme_i16i64, do_adda, a, MO_64, gen_helper_sme_addva_d)
301*558e956cSRichard Henderson 
302*558e956cSRichard Henderson static bool do_outprod_fpst(DisasContext *s, arg_op *a, MemOp esz,
303*558e956cSRichard Henderson                             gen_helper_gvec_5_ptr *fn)
304*558e956cSRichard Henderson {
305*558e956cSRichard Henderson     int svl = streaming_vec_reg_size(s);
306*558e956cSRichard Henderson     uint32_t desc = simd_desc(svl, svl, a->sub);
307*558e956cSRichard Henderson     TCGv_ptr za, zn, zm, pn, pm, fpst;
308*558e956cSRichard Henderson 
309*558e956cSRichard Henderson     if (!sme_smza_enabled_check(s)) {
310*558e956cSRichard Henderson         return true;
311*558e956cSRichard Henderson     }
312*558e956cSRichard Henderson 
313*558e956cSRichard Henderson     /* Sum XZR+zad to find ZAd. */
314*558e956cSRichard Henderson     za = get_tile_rowcol(s, esz, 31, a->zad, false);
315*558e956cSRichard Henderson     zn = vec_full_reg_ptr(s, a->zn);
316*558e956cSRichard Henderson     zm = vec_full_reg_ptr(s, a->zm);
317*558e956cSRichard Henderson     pn = pred_full_reg_ptr(s, a->pn);
318*558e956cSRichard Henderson     pm = pred_full_reg_ptr(s, a->pm);
319*558e956cSRichard Henderson     fpst = fpstatus_ptr(FPST_FPCR);
320*558e956cSRichard Henderson 
321*558e956cSRichard Henderson     fn(za, zn, zm, pn, pm, fpst, tcg_constant_i32(desc));
322*558e956cSRichard Henderson 
323*558e956cSRichard Henderson     tcg_temp_free_ptr(za);
324*558e956cSRichard Henderson     tcg_temp_free_ptr(zn);
325*558e956cSRichard Henderson     tcg_temp_free_ptr(pn);
326*558e956cSRichard Henderson     tcg_temp_free_ptr(pm);
327*558e956cSRichard Henderson     tcg_temp_free_ptr(fpst);
328*558e956cSRichard Henderson     return true;
329*558e956cSRichard Henderson }
330*558e956cSRichard Henderson 
331*558e956cSRichard Henderson TRANS_FEAT(FMOPA_s, aa64_sme, do_outprod_fpst, a, MO_32, gen_helper_sme_fmopa_s)
332*558e956cSRichard Henderson TRANS_FEAT(FMOPA_d, aa64_sme_f64f64, do_outprod_fpst, a, MO_64, gen_helper_sme_fmopa_d)
333