1/*
2 * RISC-V translation routines for the RVV Standard Extension.
3 *
4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "tcg/tcg-op-gvec.h"
19#include "tcg/tcg-gvec-desc.h"
20#include "internals.h"
21
22static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
23{
24    TCGv s1, s2, dst;
25
26    if (!has_ext(ctx, RVV)) {
27        return false;
28    }
29
30    s2 = tcg_temp_new();
31    dst = tcg_temp_new();
32
33    /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
34    if (a->rs1 == 0) {
35        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
36        s1 = tcg_const_tl(RV_VLEN_MAX);
37    } else {
38        s1 = tcg_temp_new();
39        gen_get_gpr(s1, a->rs1);
40    }
41    gen_get_gpr(s2, a->rs2);
42    gen_helper_vsetvl(dst, cpu_env, s1, s2);
43    gen_set_gpr(a->rd, dst);
44    tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
45    lookup_and_goto_ptr(ctx);
46    ctx->base.is_jmp = DISAS_NORETURN;
47
48    tcg_temp_free(s1);
49    tcg_temp_free(s2);
50    tcg_temp_free(dst);
51    return true;
52}
53
54static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
55{
56    TCGv s1, s2, dst;
57
58    if (!has_ext(ctx, RVV)) {
59        return false;
60    }
61
62    s2 = tcg_const_tl(a->zimm);
63    dst = tcg_temp_new();
64
65    /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
66    if (a->rs1 == 0) {
67        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
68        s1 = tcg_const_tl(RV_VLEN_MAX);
69    } else {
70        s1 = tcg_temp_new();
71        gen_get_gpr(s1, a->rs1);
72    }
73    gen_helper_vsetvl(dst, cpu_env, s1, s2);
74    gen_set_gpr(a->rd, dst);
75    gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
76    ctx->base.is_jmp = DISAS_NORETURN;
77
78    tcg_temp_free(s1);
79    tcg_temp_free(s2);
80    tcg_temp_free(dst);
81    return true;
82}
83
84/* vector register offset from env */
85static uint32_t vreg_ofs(DisasContext *s, int reg)
86{
87    return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
88}
89
90/* check functions */
91
92/*
93 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
94 * So RVV is also be checked in this function.
95 */
96static bool vext_check_isa_ill(DisasContext *s)
97{
98    return !s->vill;
99}
100
101/*
102 * There are two rules check here.
103 *
104 * 1. Vector register numbers are multiples of LMUL. (Section 3.2)
105 *
106 * 2. For all widening instructions, the destination LMUL value must also be
107 *    a supported LMUL value. (Section 11.2)
108 */
109static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen)
110{
111    /*
112     * The destination vector register group results are arranged as if both
113     * SEW and LMUL were at twice their current settings. (Section 11.2).
114     */
115    int legal = widen ? 2 << s->lmul : 1 << s->lmul;
116
117    return !((s->lmul == 0x3 && widen) || (reg % legal));
118}
119
120/*
121 * There are two rules check here.
122 *
123 * 1. The destination vector register group for a masked vector instruction can
124 *    only overlap the source mask register (v0) when LMUL=1. (Section 5.3)
125 *
126 * 2. In widen instructions and some other insturctions, like vslideup.vx,
127 *    there is no need to check whether LMUL=1.
128 */
129static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm,
130    bool force)
131{
132    return (vm != 0 || vd != 0) || (!force && (s->lmul == 0));
133}
134
135/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */
136static bool vext_check_nf(DisasContext *s, uint32_t nf)
137{
138    return (1 << s->lmul) * nf <= 8;
139}
140
141/*
142 * The destination vector register group cannot overlap a source vector register
143 * group of a different element width. (Section 11.2)
144 */
145static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen)
146{
147    return ((rd >= rs + slen) || (rs >= rd + dlen));
148}
149/* common translation macro */
150#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK)      \
151static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\
152{                                                          \
153    if (CHECK(s, a)) {                                     \
154        return OP(s, a, SEQ);                              \
155    }                                                      \
156    return false;                                          \
157}
158
159/*
160 *** unit stride load and store
161 */
162typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
163                                TCGv_env, TCGv_i32);
164
165static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
166                          gen_helper_ldst_us *fn, DisasContext *s)
167{
168    TCGv_ptr dest, mask;
169    TCGv base;
170    TCGv_i32 desc;
171
172    TCGLabel *over = gen_new_label();
173    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
174
175    dest = tcg_temp_new_ptr();
176    mask = tcg_temp_new_ptr();
177    base = tcg_temp_new();
178
179    /*
180     * As simd_desc supports at most 256 bytes, and in this implementation,
181     * the max vector group length is 2048 bytes. So split it into two parts.
182     *
183     * The first part is vlen in bytes, encoded in maxsz of simd_desc.
184     * The second part is lmul, encoded in data of simd_desc.
185     */
186    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
187
188    gen_get_gpr(base, rs1);
189    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
190    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
191
192    fn(dest, mask, base, cpu_env, desc);
193
194    tcg_temp_free_ptr(dest);
195    tcg_temp_free_ptr(mask);
196    tcg_temp_free(base);
197    tcg_temp_free_i32(desc);
198    gen_set_label(over);
199    return true;
200}
201
202static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
203{
204    uint32_t data = 0;
205    gen_helper_ldst_us *fn;
206    static gen_helper_ldst_us * const fns[2][7][4] = {
207        /* masked unit stride load */
208        { { gen_helper_vlb_v_b_mask,  gen_helper_vlb_v_h_mask,
209            gen_helper_vlb_v_w_mask,  gen_helper_vlb_v_d_mask },
210          { NULL,                     gen_helper_vlh_v_h_mask,
211            gen_helper_vlh_v_w_mask,  gen_helper_vlh_v_d_mask },
212          { NULL,                     NULL,
213            gen_helper_vlw_v_w_mask,  gen_helper_vlw_v_d_mask },
214          { gen_helper_vle_v_b_mask,  gen_helper_vle_v_h_mask,
215            gen_helper_vle_v_w_mask,  gen_helper_vle_v_d_mask },
216          { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask,
217            gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask },
218          { NULL,                     gen_helper_vlhu_v_h_mask,
219            gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask },
220          { NULL,                     NULL,
221            gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } },
222        /* unmasked unit stride load */
223        { { gen_helper_vlb_v_b,  gen_helper_vlb_v_h,
224            gen_helper_vlb_v_w,  gen_helper_vlb_v_d },
225          { NULL,                gen_helper_vlh_v_h,
226            gen_helper_vlh_v_w,  gen_helper_vlh_v_d },
227          { NULL,                NULL,
228            gen_helper_vlw_v_w,  gen_helper_vlw_v_d },
229          { gen_helper_vle_v_b,  gen_helper_vle_v_h,
230            gen_helper_vle_v_w,  gen_helper_vle_v_d },
231          { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h,
232            gen_helper_vlbu_v_w, gen_helper_vlbu_v_d },
233          { NULL,                gen_helper_vlhu_v_h,
234            gen_helper_vlhu_v_w, gen_helper_vlhu_v_d },
235          { NULL,                NULL,
236            gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } }
237    };
238
239    fn =  fns[a->vm][seq][s->sew];
240    if (fn == NULL) {
241        return false;
242    }
243
244    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
245    data = FIELD_DP32(data, VDATA, VM, a->vm);
246    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
247    data = FIELD_DP32(data, VDATA, NF, a->nf);
248    return ldst_us_trans(a->rd, a->rs1, data, fn, s);
249}
250
251static bool ld_us_check(DisasContext *s, arg_r2nfvm* a)
252{
253    return (vext_check_isa_ill(s) &&
254            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
255            vext_check_reg(s, a->rd, false) &&
256            vext_check_nf(s, a->nf));
257}
258
259GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check)
260GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check)
261GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check)
262GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check)
263GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check)
264GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check)
265GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check)
266
267static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
268{
269    uint32_t data = 0;
270    gen_helper_ldst_us *fn;
271    static gen_helper_ldst_us * const fns[2][4][4] = {
272        /* masked unit stride load and store */
273        { { gen_helper_vsb_v_b_mask,  gen_helper_vsb_v_h_mask,
274            gen_helper_vsb_v_w_mask,  gen_helper_vsb_v_d_mask },
275          { NULL,                     gen_helper_vsh_v_h_mask,
276            gen_helper_vsh_v_w_mask,  gen_helper_vsh_v_d_mask },
277          { NULL,                     NULL,
278            gen_helper_vsw_v_w_mask,  gen_helper_vsw_v_d_mask },
279          { gen_helper_vse_v_b_mask,  gen_helper_vse_v_h_mask,
280            gen_helper_vse_v_w_mask,  gen_helper_vse_v_d_mask } },
281        /* unmasked unit stride store */
282        { { gen_helper_vsb_v_b,  gen_helper_vsb_v_h,
283            gen_helper_vsb_v_w,  gen_helper_vsb_v_d },
284          { NULL,                gen_helper_vsh_v_h,
285            gen_helper_vsh_v_w,  gen_helper_vsh_v_d },
286          { NULL,                NULL,
287            gen_helper_vsw_v_w,  gen_helper_vsw_v_d },
288          { gen_helper_vse_v_b,  gen_helper_vse_v_h,
289            gen_helper_vse_v_w,  gen_helper_vse_v_d } }
290    };
291
292    fn =  fns[a->vm][seq][s->sew];
293    if (fn == NULL) {
294        return false;
295    }
296
297    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
298    data = FIELD_DP32(data, VDATA, VM, a->vm);
299    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
300    data = FIELD_DP32(data, VDATA, NF, a->nf);
301    return ldst_us_trans(a->rd, a->rs1, data, fn, s);
302}
303
304static bool st_us_check(DisasContext *s, arg_r2nfvm* a)
305{
306    return (vext_check_isa_ill(s) &&
307            vext_check_reg(s, a->rd, false) &&
308            vext_check_nf(s, a->nf));
309}
310
311GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check)
312GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check)
313GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check)
314GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check)
315
316/*
317 *** stride load and store
318 */
319typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
320                                    TCGv, TCGv_env, TCGv_i32);
321
322static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
323                              uint32_t data, gen_helper_ldst_stride *fn,
324                              DisasContext *s)
325{
326    TCGv_ptr dest, mask;
327    TCGv base, stride;
328    TCGv_i32 desc;
329
330    TCGLabel *over = gen_new_label();
331    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
332
333    dest = tcg_temp_new_ptr();
334    mask = tcg_temp_new_ptr();
335    base = tcg_temp_new();
336    stride = tcg_temp_new();
337    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
338
339    gen_get_gpr(base, rs1);
340    gen_get_gpr(stride, rs2);
341    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
342    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
343
344    fn(dest, mask, base, stride, cpu_env, desc);
345
346    tcg_temp_free_ptr(dest);
347    tcg_temp_free_ptr(mask);
348    tcg_temp_free(base);
349    tcg_temp_free(stride);
350    tcg_temp_free_i32(desc);
351    gen_set_label(over);
352    return true;
353}
354
355static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
356{
357    uint32_t data = 0;
358    gen_helper_ldst_stride *fn;
359    static gen_helper_ldst_stride * const fns[7][4] = {
360        { gen_helper_vlsb_v_b,  gen_helper_vlsb_v_h,
361          gen_helper_vlsb_v_w,  gen_helper_vlsb_v_d },
362        { NULL,                 gen_helper_vlsh_v_h,
363          gen_helper_vlsh_v_w,  gen_helper_vlsh_v_d },
364        { NULL,                 NULL,
365          gen_helper_vlsw_v_w,  gen_helper_vlsw_v_d },
366        { gen_helper_vlse_v_b,  gen_helper_vlse_v_h,
367          gen_helper_vlse_v_w,  gen_helper_vlse_v_d },
368        { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h,
369          gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d },
370        { NULL,                 gen_helper_vlshu_v_h,
371          gen_helper_vlshu_v_w, gen_helper_vlshu_v_d },
372        { NULL,                 NULL,
373          gen_helper_vlswu_v_w, gen_helper_vlswu_v_d },
374    };
375
376    fn =  fns[seq][s->sew];
377    if (fn == NULL) {
378        return false;
379    }
380
381    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
382    data = FIELD_DP32(data, VDATA, VM, a->vm);
383    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
384    data = FIELD_DP32(data, VDATA, NF, a->nf);
385    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
386}
387
388static bool ld_stride_check(DisasContext *s, arg_rnfvm* a)
389{
390    return (vext_check_isa_ill(s) &&
391            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
392            vext_check_reg(s, a->rd, false) &&
393            vext_check_nf(s, a->nf));
394}
395
396GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check)
397GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check)
398GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check)
399GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check)
400GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check)
401GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check)
402GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check)
403
404static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
405{
406    uint32_t data = 0;
407    gen_helper_ldst_stride *fn;
408    static gen_helper_ldst_stride * const fns[4][4] = {
409        /* masked stride store */
410        { gen_helper_vssb_v_b,  gen_helper_vssb_v_h,
411          gen_helper_vssb_v_w,  gen_helper_vssb_v_d },
412        { NULL,                 gen_helper_vssh_v_h,
413          gen_helper_vssh_v_w,  gen_helper_vssh_v_d },
414        { NULL,                 NULL,
415          gen_helper_vssw_v_w,  gen_helper_vssw_v_d },
416        { gen_helper_vsse_v_b,  gen_helper_vsse_v_h,
417          gen_helper_vsse_v_w,  gen_helper_vsse_v_d }
418    };
419
420    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
421    data = FIELD_DP32(data, VDATA, VM, a->vm);
422    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
423    data = FIELD_DP32(data, VDATA, NF, a->nf);
424    fn =  fns[seq][s->sew];
425    if (fn == NULL) {
426        return false;
427    }
428
429    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s);
430}
431
432static bool st_stride_check(DisasContext *s, arg_rnfvm* a)
433{
434    return (vext_check_isa_ill(s) &&
435            vext_check_reg(s, a->rd, false) &&
436            vext_check_nf(s, a->nf));
437}
438
439GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check)
440GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check)
441GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check)
442GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check)
443
444/*
445 *** index load and store
446 */
447typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
448                                   TCGv_ptr, TCGv_env, TCGv_i32);
449
450static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
451                             uint32_t data, gen_helper_ldst_index *fn,
452                             DisasContext *s)
453{
454    TCGv_ptr dest, mask, index;
455    TCGv base;
456    TCGv_i32 desc;
457
458    TCGLabel *over = gen_new_label();
459    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
460
461    dest = tcg_temp_new_ptr();
462    mask = tcg_temp_new_ptr();
463    index = tcg_temp_new_ptr();
464    base = tcg_temp_new();
465    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
466
467    gen_get_gpr(base, rs1);
468    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
469    tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
470    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
471
472    fn(dest, mask, base, index, cpu_env, desc);
473
474    tcg_temp_free_ptr(dest);
475    tcg_temp_free_ptr(mask);
476    tcg_temp_free_ptr(index);
477    tcg_temp_free(base);
478    tcg_temp_free_i32(desc);
479    gen_set_label(over);
480    return true;
481}
482
483static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
484{
485    uint32_t data = 0;
486    gen_helper_ldst_index *fn;
487    static gen_helper_ldst_index * const fns[7][4] = {
488        { gen_helper_vlxb_v_b,  gen_helper_vlxb_v_h,
489          gen_helper_vlxb_v_w,  gen_helper_vlxb_v_d },
490        { NULL,                 gen_helper_vlxh_v_h,
491          gen_helper_vlxh_v_w,  gen_helper_vlxh_v_d },
492        { NULL,                 NULL,
493          gen_helper_vlxw_v_w,  gen_helper_vlxw_v_d },
494        { gen_helper_vlxe_v_b,  gen_helper_vlxe_v_h,
495          gen_helper_vlxe_v_w,  gen_helper_vlxe_v_d },
496        { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h,
497          gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d },
498        { NULL,                 gen_helper_vlxhu_v_h,
499          gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d },
500        { NULL,                 NULL,
501          gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d },
502    };
503
504    fn =  fns[seq][s->sew];
505    if (fn == NULL) {
506        return false;
507    }
508
509    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
510    data = FIELD_DP32(data, VDATA, VM, a->vm);
511    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
512    data = FIELD_DP32(data, VDATA, NF, a->nf);
513    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
514}
515
516/*
517 * For vector indexed segment loads, the destination vector register
518 * groups cannot overlap the source vector register group (specified by
519 * `vs2`), else an illegal instruction exception is raised.
520 */
521static bool ld_index_check(DisasContext *s, arg_rnfvm* a)
522{
523    return (vext_check_isa_ill(s) &&
524            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
525            vext_check_reg(s, a->rd, false) &&
526            vext_check_reg(s, a->rs2, false) &&
527            vext_check_nf(s, a->nf) &&
528            ((a->nf == 1) ||
529             vext_check_overlap_group(a->rd, a->nf << s->lmul,
530                                      a->rs2, 1 << s->lmul)));
531}
532
533GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check)
534GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check)
535GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check)
536GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check)
537GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check)
538GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check)
539GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check)
540
541static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
542{
543    uint32_t data = 0;
544    gen_helper_ldst_index *fn;
545    static gen_helper_ldst_index * const fns[4][4] = {
546        { gen_helper_vsxb_v_b,  gen_helper_vsxb_v_h,
547          gen_helper_vsxb_v_w,  gen_helper_vsxb_v_d },
548        { NULL,                 gen_helper_vsxh_v_h,
549          gen_helper_vsxh_v_w,  gen_helper_vsxh_v_d },
550        { NULL,                 NULL,
551          gen_helper_vsxw_v_w,  gen_helper_vsxw_v_d },
552        { gen_helper_vsxe_v_b,  gen_helper_vsxe_v_h,
553          gen_helper_vsxe_v_w,  gen_helper_vsxe_v_d }
554    };
555
556    fn =  fns[seq][s->sew];
557    if (fn == NULL) {
558        return false;
559    }
560
561    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
562    data = FIELD_DP32(data, VDATA, VM, a->vm);
563    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
564    data = FIELD_DP32(data, VDATA, NF, a->nf);
565    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s);
566}
567
568static bool st_index_check(DisasContext *s, arg_rnfvm* a)
569{
570    return (vext_check_isa_ill(s) &&
571            vext_check_reg(s, a->rd, false) &&
572            vext_check_reg(s, a->rs2, false) &&
573            vext_check_nf(s, a->nf));
574}
575
576GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check)
577GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check)
578GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check)
579GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check)
580
581/*
582 *** unit stride fault-only-first load
583 */
584static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
585                       gen_helper_ldst_us *fn, DisasContext *s)
586{
587    TCGv_ptr dest, mask;
588    TCGv base;
589    TCGv_i32 desc;
590
591    TCGLabel *over = gen_new_label();
592    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
593
594    dest = tcg_temp_new_ptr();
595    mask = tcg_temp_new_ptr();
596    base = tcg_temp_new();
597    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
598
599    gen_get_gpr(base, rs1);
600    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
601    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
602
603    fn(dest, mask, base, cpu_env, desc);
604
605    tcg_temp_free_ptr(dest);
606    tcg_temp_free_ptr(mask);
607    tcg_temp_free(base);
608    tcg_temp_free_i32(desc);
609    gen_set_label(over);
610    return true;
611}
612
613static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
614{
615    uint32_t data = 0;
616    gen_helper_ldst_us *fn;
617    static gen_helper_ldst_us * const fns[7][4] = {
618        { gen_helper_vlbff_v_b,  gen_helper_vlbff_v_h,
619          gen_helper_vlbff_v_w,  gen_helper_vlbff_v_d },
620        { NULL,                  gen_helper_vlhff_v_h,
621          gen_helper_vlhff_v_w,  gen_helper_vlhff_v_d },
622        { NULL,                  NULL,
623          gen_helper_vlwff_v_w,  gen_helper_vlwff_v_d },
624        { gen_helper_vleff_v_b,  gen_helper_vleff_v_h,
625          gen_helper_vleff_v_w,  gen_helper_vleff_v_d },
626        { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h,
627          gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d },
628        { NULL,                  gen_helper_vlhuff_v_h,
629          gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d },
630        { NULL,                  NULL,
631          gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d }
632    };
633
634    fn =  fns[seq][s->sew];
635    if (fn == NULL) {
636        return false;
637    }
638
639    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
640    data = FIELD_DP32(data, VDATA, VM, a->vm);
641    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
642    data = FIELD_DP32(data, VDATA, NF, a->nf);
643    return ldff_trans(a->rd, a->rs1, data, fn, s);
644}
645
646GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check)
647GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check)
648GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check)
649GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check)
650GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check)
651GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check)
652GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check)
653
654/*
655 *** vector atomic operation
656 */
657typedef void gen_helper_amo(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
658                            TCGv_env, TCGv_i32);
659
660static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
661                      uint32_t data, gen_helper_amo *fn, DisasContext *s)
662{
663    TCGv_ptr dest, mask, index;
664    TCGv base;
665    TCGv_i32 desc;
666
667    TCGLabel *over = gen_new_label();
668    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
669
670    dest = tcg_temp_new_ptr();
671    mask = tcg_temp_new_ptr();
672    index = tcg_temp_new_ptr();
673    base = tcg_temp_new();
674    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
675
676    gen_get_gpr(base, rs1);
677    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
678    tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
679    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
680
681    fn(dest, mask, base, index, cpu_env, desc);
682
683    tcg_temp_free_ptr(dest);
684    tcg_temp_free_ptr(mask);
685    tcg_temp_free_ptr(index);
686    tcg_temp_free(base);
687    tcg_temp_free_i32(desc);
688    gen_set_label(over);
689    return true;
690}
691
692static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
693{
694    uint32_t data = 0;
695    gen_helper_amo *fn;
696    static gen_helper_amo *const fnsw[9] = {
697        /* no atomic operation */
698        gen_helper_vamoswapw_v_w,
699        gen_helper_vamoaddw_v_w,
700        gen_helper_vamoxorw_v_w,
701        gen_helper_vamoandw_v_w,
702        gen_helper_vamoorw_v_w,
703        gen_helper_vamominw_v_w,
704        gen_helper_vamomaxw_v_w,
705        gen_helper_vamominuw_v_w,
706        gen_helper_vamomaxuw_v_w
707    };
708    static gen_helper_amo *const fnsd[18] = {
709        gen_helper_vamoswapw_v_d,
710        gen_helper_vamoaddw_v_d,
711        gen_helper_vamoxorw_v_d,
712        gen_helper_vamoandw_v_d,
713        gen_helper_vamoorw_v_d,
714        gen_helper_vamominw_v_d,
715        gen_helper_vamomaxw_v_d,
716        gen_helper_vamominuw_v_d,
717        gen_helper_vamomaxuw_v_d,
718        gen_helper_vamoswapd_v_d,
719        gen_helper_vamoaddd_v_d,
720        gen_helper_vamoxord_v_d,
721        gen_helper_vamoandd_v_d,
722        gen_helper_vamoord_v_d,
723        gen_helper_vamomind_v_d,
724        gen_helper_vamomaxd_v_d,
725        gen_helper_vamominud_v_d,
726        gen_helper_vamomaxud_v_d
727    };
728
729    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
730        gen_helper_exit_atomic(cpu_env);
731        s->base.is_jmp = DISAS_NORETURN;
732        return true;
733    } else {
734        if (s->sew == 3) {
735            if (!is_32bit(s)) {
736                fn = fnsd[seq];
737            } else {
738                /* Check done in amo_check(). */
739                g_assert_not_reached();
740            }
741        } else {
742            assert(seq < ARRAY_SIZE(fnsw));
743            fn = fnsw[seq];
744        }
745    }
746
747    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
748    data = FIELD_DP32(data, VDATA, VM, a->vm);
749    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
750    data = FIELD_DP32(data, VDATA, WD, a->wd);
751    return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s);
752}
753/*
754 * There are two rules check here.
755 *
756 * 1. SEW must be at least as wide as the AMO memory element size.
757 *
758 * 2. If SEW is greater than XLEN, an illegal instruction exception is raised.
759 */
760static bool amo_check(DisasContext *s, arg_rwdvm* a)
761{
762    return (!s->vill && has_ext(s, RVA) &&
763            (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) &&
764            vext_check_reg(s, a->rd, false) &&
765            vext_check_reg(s, a->rs2, false) &&
766            ((1 << s->sew) <= sizeof(target_ulong)) &&
767            ((1 << s->sew) >= 4));
768}
769
770static bool amo_check64(DisasContext *s, arg_rwdvm* a)
771{
772    return !is_32bit(s) && amo_check(s, a);
773}
774
775GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check)
776GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check)
777GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check)
778GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check)
779GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check)
780GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check)
781GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check)
782GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check)
783GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check)
784GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64)
785GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64)
786GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64)
787GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64)
788GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64)
789GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64)
790GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64)
791GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64)
792GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64)
793
794/*
795 *** Vector Integer Arithmetic Instructions
796 */
797#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
798
799static bool opivv_check(DisasContext *s, arg_rmrr *a)
800{
801    return (vext_check_isa_ill(s) &&
802            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
803            vext_check_reg(s, a->rd, false) &&
804            vext_check_reg(s, a->rs2, false) &&
805            vext_check_reg(s, a->rs1, false));
806}
807
808typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
809                        uint32_t, uint32_t, uint32_t);
810
811static inline bool
812do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
813              gen_helper_gvec_4_ptr *fn)
814{
815    TCGLabel *over = gen_new_label();
816    if (!opivv_check(s, a)) {
817        return false;
818    }
819
820    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
821
822    if (a->vm && s->vl_eq_vlmax) {
823        gvec_fn(s->sew, vreg_ofs(s, a->rd),
824                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
825                MAXSZ(s), MAXSZ(s));
826    } else {
827        uint32_t data = 0;
828
829        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
830        data = FIELD_DP32(data, VDATA, VM, a->vm);
831        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
832        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
833                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
834                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
835    }
836    gen_set_label(over);
837    return true;
838}
839
840/* OPIVV with GVEC IR */
841#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
842static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
843{                                                                  \
844    static gen_helper_gvec_4_ptr * const fns[4] = {                \
845        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
846        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
847    };                                                             \
848    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
849}
850
851GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
852GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
853
854typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
855                              TCGv_env, TCGv_i32);
856
857static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
858                        gen_helper_opivx *fn, DisasContext *s)
859{
860    TCGv_ptr dest, src2, mask;
861    TCGv src1;
862    TCGv_i32 desc;
863    uint32_t data = 0;
864
865    TCGLabel *over = gen_new_label();
866    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
867
868    dest = tcg_temp_new_ptr();
869    mask = tcg_temp_new_ptr();
870    src2 = tcg_temp_new_ptr();
871    src1 = tcg_temp_new();
872    gen_get_gpr(src1, rs1);
873
874    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
875    data = FIELD_DP32(data, VDATA, VM, vm);
876    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
877    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
878
879    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
880    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
881    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
882
883    fn(dest, mask, src1, src2, cpu_env, desc);
884
885    tcg_temp_free_ptr(dest);
886    tcg_temp_free_ptr(mask);
887    tcg_temp_free_ptr(src2);
888    tcg_temp_free(src1);
889    tcg_temp_free_i32(desc);
890    gen_set_label(over);
891    return true;
892}
893
894static bool opivx_check(DisasContext *s, arg_rmrr *a)
895{
896    return (vext_check_isa_ill(s) &&
897            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
898            vext_check_reg(s, a->rd, false) &&
899            vext_check_reg(s, a->rs2, false));
900}
901
902typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
903                         uint32_t, uint32_t);
904
905static inline bool
906do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
907              gen_helper_opivx *fn)
908{
909    if (!opivx_check(s, a)) {
910        return false;
911    }
912
913    if (a->vm && s->vl_eq_vlmax) {
914        TCGv_i64 src1 = tcg_temp_new_i64();
915        TCGv tmp = tcg_temp_new();
916
917        gen_get_gpr(tmp, a->rs1);
918        tcg_gen_ext_tl_i64(src1, tmp);
919        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
920                src1, MAXSZ(s), MAXSZ(s));
921
922        tcg_temp_free_i64(src1);
923        tcg_temp_free(tmp);
924        return true;
925    }
926    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
927}
928
929/* OPIVX with GVEC IR */
930#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
931static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
932{                                                                  \
933    static gen_helper_opivx * const fns[4] = {                     \
934        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
935        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
936    };                                                             \
937    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
938}
939
940GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
941GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
942
943static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
944{
945    tcg_gen_vec_sub8_i64(d, b, a);
946}
947
948static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
949{
950    tcg_gen_vec_sub16_i64(d, b, a);
951}
952
953static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
954{
955    tcg_gen_sub_i32(ret, arg2, arg1);
956}
957
958static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
959{
960    tcg_gen_sub_i64(ret, arg2, arg1);
961}
962
963static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
964{
965    tcg_gen_sub_vec(vece, r, b, a);
966}
967
968static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
969                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
970{
971    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
972    static const GVecGen2s rsub_op[4] = {
973        { .fni8 = gen_vec_rsub8_i64,
974          .fniv = gen_rsub_vec,
975          .fno = gen_helper_vec_rsubs8,
976          .opt_opc = vecop_list,
977          .vece = MO_8 },
978        { .fni8 = gen_vec_rsub16_i64,
979          .fniv = gen_rsub_vec,
980          .fno = gen_helper_vec_rsubs16,
981          .opt_opc = vecop_list,
982          .vece = MO_16 },
983        { .fni4 = gen_rsub_i32,
984          .fniv = gen_rsub_vec,
985          .fno = gen_helper_vec_rsubs32,
986          .opt_opc = vecop_list,
987          .vece = MO_32 },
988        { .fni8 = gen_rsub_i64,
989          .fniv = gen_rsub_vec,
990          .fno = gen_helper_vec_rsubs64,
991          .opt_opc = vecop_list,
992          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
993          .vece = MO_64 },
994    };
995
996    tcg_debug_assert(vece <= MO_64);
997    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
998}
999
1000GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1001
1002static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1003                        gen_helper_opivx *fn, DisasContext *s, int zx)
1004{
1005    TCGv_ptr dest, src2, mask;
1006    TCGv src1;
1007    TCGv_i32 desc;
1008    uint32_t data = 0;
1009
1010    TCGLabel *over = gen_new_label();
1011    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1012
1013    dest = tcg_temp_new_ptr();
1014    mask = tcg_temp_new_ptr();
1015    src2 = tcg_temp_new_ptr();
1016    if (zx) {
1017        src1 = tcg_const_tl(imm);
1018    } else {
1019        src1 = tcg_const_tl(sextract64(imm, 0, 5));
1020    }
1021    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
1022    data = FIELD_DP32(data, VDATA, VM, vm);
1023    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1024    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1025
1026    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1027    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1028    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1029
1030    fn(dest, mask, src1, src2, cpu_env, desc);
1031
1032    tcg_temp_free_ptr(dest);
1033    tcg_temp_free_ptr(mask);
1034    tcg_temp_free_ptr(src2);
1035    tcg_temp_free(src1);
1036    tcg_temp_free_i32(desc);
1037    gen_set_label(over);
1038    return true;
1039}
1040
1041typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1042                         uint32_t, uint32_t);
1043
1044static inline bool
1045do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1046              gen_helper_opivx *fn, int zx)
1047{
1048    if (!opivx_check(s, a)) {
1049        return false;
1050    }
1051
1052    if (a->vm && s->vl_eq_vlmax) {
1053        if (zx) {
1054            gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1055                    extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
1056        } else {
1057            gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1058                    sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
1059        }
1060    } else {
1061        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx);
1062    }
1063    return true;
1064}
1065
1066/* OPIVI with GVEC IR */
1067#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
1068static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1069{                                                                  \
1070    static gen_helper_opivx * const fns[4] = {                     \
1071        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1072        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1073    };                                                             \
1074    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1075                         fns[s->sew], ZX);                         \
1076}
1077
1078GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi)
1079
1080static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1081                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1082{
1083    TCGv_i64 tmp = tcg_const_i64(c);
1084    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1085    tcg_temp_free_i64(tmp);
1086}
1087
1088GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi)
1089
1090/* Vector Widening Integer Add/Subtract */
1091
1092/* OPIVV with WIDEN */
1093static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1094{
1095    return (vext_check_isa_ill(s) &&
1096            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1097            vext_check_reg(s, a->rd, true) &&
1098            vext_check_reg(s, a->rs2, false) &&
1099            vext_check_reg(s, a->rs1, false) &&
1100            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1101                                     1 << s->lmul) &&
1102            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1103                                     1 << s->lmul) &&
1104            (s->lmul < 0x3) && (s->sew < 0x3));
1105}
1106
1107static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1108                           gen_helper_gvec_4_ptr *fn,
1109                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1110{
1111    if (checkfn(s, a)) {
1112        uint32_t data = 0;
1113        TCGLabel *over = gen_new_label();
1114        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1115
1116        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
1117        data = FIELD_DP32(data, VDATA, VM, a->vm);
1118        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1119        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1120                           vreg_ofs(s, a->rs1),
1121                           vreg_ofs(s, a->rs2),
1122                           cpu_env, s->vlen / 8, s->vlen / 8,
1123                           data, fn);
1124        gen_set_label(over);
1125        return true;
1126    }
1127    return false;
1128}
1129
1130#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1131static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1132{                                                            \
1133    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1134        gen_helper_##NAME##_b,                               \
1135        gen_helper_##NAME##_h,                               \
1136        gen_helper_##NAME##_w                                \
1137    };                                                       \
1138    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1139}
1140
1141GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1142GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1143GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1144GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1145
1146/* OPIVX with WIDEN */
1147static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1148{
1149    return (vext_check_isa_ill(s) &&
1150            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1151            vext_check_reg(s, a->rd, true) &&
1152            vext_check_reg(s, a->rs2, false) &&
1153            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1154                                     1 << s->lmul) &&
1155            (s->lmul < 0x3) && (s->sew < 0x3));
1156}
1157
1158static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1159                           gen_helper_opivx *fn)
1160{
1161    if (opivx_widen_check(s, a)) {
1162        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1163    }
1164    return false;
1165}
1166
1167#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1168static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1169{                                                            \
1170    static gen_helper_opivx * const fns[3] = {               \
1171        gen_helper_##NAME##_b,                               \
1172        gen_helper_##NAME##_h,                               \
1173        gen_helper_##NAME##_w                                \
1174    };                                                       \
1175    return do_opivx_widen(s, a, fns[s->sew]);                \
1176}
1177
1178GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1179GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1180GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1181GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1182
1183/* WIDEN OPIVV with WIDEN */
1184static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1185{
1186    return (vext_check_isa_ill(s) &&
1187            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1188            vext_check_reg(s, a->rd, true) &&
1189            vext_check_reg(s, a->rs2, true) &&
1190            vext_check_reg(s, a->rs1, false) &&
1191            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1192                                     1 << s->lmul) &&
1193            (s->lmul < 0x3) && (s->sew < 0x3));
1194}
1195
1196static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1197                           gen_helper_gvec_4_ptr *fn)
1198{
1199    if (opiwv_widen_check(s, a)) {
1200        uint32_t data = 0;
1201        TCGLabel *over = gen_new_label();
1202        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1203
1204        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
1205        data = FIELD_DP32(data, VDATA, VM, a->vm);
1206        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1207        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1208                           vreg_ofs(s, a->rs1),
1209                           vreg_ofs(s, a->rs2),
1210                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1211        gen_set_label(over);
1212        return true;
1213    }
1214    return false;
1215}
1216
1217#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1218static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1219{                                                            \
1220    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1221        gen_helper_##NAME##_b,                               \
1222        gen_helper_##NAME##_h,                               \
1223        gen_helper_##NAME##_w                                \
1224    };                                                       \
1225    return do_opiwv_widen(s, a, fns[s->sew]);                \
1226}
1227
1228GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1229GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1230GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1231GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1232
1233/* WIDEN OPIVX with WIDEN */
1234static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1235{
1236    return (vext_check_isa_ill(s) &&
1237            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1238            vext_check_reg(s, a->rd, true) &&
1239            vext_check_reg(s, a->rs2, true) &&
1240            (s->lmul < 0x3) && (s->sew < 0x3));
1241}
1242
1243static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1244                           gen_helper_opivx *fn)
1245{
1246    if (opiwx_widen_check(s, a)) {
1247        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1248    }
1249    return false;
1250}
1251
1252#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1253static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1254{                                                            \
1255    static gen_helper_opivx * const fns[3] = {               \
1256        gen_helper_##NAME##_b,                               \
1257        gen_helper_##NAME##_h,                               \
1258        gen_helper_##NAME##_w                                \
1259    };                                                       \
1260    return do_opiwx_widen(s, a, fns[s->sew]);                \
1261}
1262
1263GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1264GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1265GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1266GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1267
1268/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1269/* OPIVV without GVEC IR */
1270#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1271static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1272{                                                                  \
1273    if (CHECK(s, a)) {                                             \
1274        uint32_t data = 0;                                         \
1275        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1276            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1277            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1278        };                                                         \
1279        TCGLabel *over = gen_new_label();                          \
1280        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1281                                                                   \
1282        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1283        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1284        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1285        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1286                           vreg_ofs(s, a->rs1),                    \
1287                           vreg_ofs(s, a->rs2), cpu_env,           \
1288                           s->vlen / 8, s->vlen / 8, data,         \
1289                           fns[s->sew]);                           \
1290        gen_set_label(over);                                       \
1291        return true;                                               \
1292    }                                                              \
1293    return false;                                                  \
1294}
1295
1296/*
1297 * For vadc and vsbc, an illegal instruction exception is raised if the
1298 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1299 */
1300static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1301{
1302    return (vext_check_isa_ill(s) &&
1303            vext_check_reg(s, a->rd, false) &&
1304            vext_check_reg(s, a->rs2, false) &&
1305            vext_check_reg(s, a->rs1, false) &&
1306            ((a->rd != 0) || (s->lmul == 0)));
1307}
1308
1309GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1310GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1311
1312/*
1313 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1314 * destination vector register overlaps a source vector register group.
1315 */
1316static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1317{
1318    return (vext_check_isa_ill(s) &&
1319            vext_check_reg(s, a->rs2, false) &&
1320            vext_check_reg(s, a->rs1, false) &&
1321            vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
1322            vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
1323}
1324
1325GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1326GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1327
1328static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1329{
1330    return (vext_check_isa_ill(s) &&
1331            vext_check_reg(s, a->rd, false) &&
1332            vext_check_reg(s, a->rs2, false) &&
1333            ((a->rd != 0) || (s->lmul == 0)));
1334}
1335
1336/* OPIVX without GVEC IR */
1337#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1338static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1339{                                                                        \
1340    if (CHECK(s, a)) {                                                   \
1341        static gen_helper_opivx * const fns[4] = {                       \
1342            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1343            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1344        };                                                               \
1345                                                                         \
1346        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1347    }                                                                    \
1348    return false;                                                        \
1349}
1350
1351GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1352GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1353
1354static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1355{
1356    return (vext_check_isa_ill(s) &&
1357            vext_check_reg(s, a->rs2, false) &&
1358            vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
1359}
1360
1361GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1362GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1363
1364/* OPIVI without GVEC IR */
1365#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK)                          \
1366static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1367{                                                                        \
1368    if (CHECK(s, a)) {                                                   \
1369        static gen_helper_opivx * const fns[4] = {                       \
1370            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1371            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1372        };                                                               \
1373        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1374                           fns[s->sew], s, ZX);                          \
1375    }                                                                    \
1376    return false;                                                        \
1377}
1378
1379GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check)
1380GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check)
1381
1382/* Vector Bitwise Logical Instructions */
1383GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1384GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1385GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1386GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1387GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1388GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1389GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi)
1390GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx,  ori)
1391GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori)
1392
1393/* Vector Single-Width Bit Shift Instructions */
1394GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1395GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1396GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1397
1398typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1399                           uint32_t, uint32_t);
1400
1401static inline bool
1402do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1403                    gen_helper_opivx *fn)
1404{
1405    if (!opivx_check(s, a)) {
1406        return false;
1407    }
1408
1409    if (a->vm && s->vl_eq_vlmax) {
1410        TCGv_i32 src1 = tcg_temp_new_i32();
1411        TCGv tmp = tcg_temp_new();
1412
1413        gen_get_gpr(tmp, a->rs1);
1414        tcg_gen_trunc_tl_i32(src1, tmp);
1415        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1416        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1417                src1, MAXSZ(s), MAXSZ(s));
1418
1419        tcg_temp_free_i32(src1);
1420        tcg_temp_free(tmp);
1421        return true;
1422    }
1423    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1424}
1425
1426#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1427static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1428{                                                                         \
1429    static gen_helper_opivx * const fns[4] = {                            \
1430        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1431        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1432    };                                                                    \
1433                                                                          \
1434    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1435}
1436
1437GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1438GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1439GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1440
1441GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx,  shli)
1442GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx,  shri)
1443GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx,  sari)
1444
1445/* Vector Narrowing Integer Right Shift Instructions */
1446static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
1447{
1448    return (vext_check_isa_ill(s) &&
1449            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1450            vext_check_reg(s, a->rd, false) &&
1451            vext_check_reg(s, a->rs2, true) &&
1452            vext_check_reg(s, a->rs1, false) &&
1453            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
1454                2 << s->lmul) &&
1455            (s->lmul < 0x3) && (s->sew < 0x3));
1456}
1457
1458/* OPIVV with NARROW */
1459#define GEN_OPIVV_NARROW_TRANS(NAME)                               \
1460static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1461{                                                                  \
1462    if (opivv_narrow_check(s, a)) {                                \
1463        uint32_t data = 0;                                         \
1464        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1465            gen_helper_##NAME##_b,                                 \
1466            gen_helper_##NAME##_h,                                 \
1467            gen_helper_##NAME##_w,                                 \
1468        };                                                         \
1469        TCGLabel *over = gen_new_label();                          \
1470        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1471                                                                   \
1472        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1473        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1474        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1475        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1476                           vreg_ofs(s, a->rs1),                    \
1477                           vreg_ofs(s, a->rs2), cpu_env,           \
1478                           s->vlen / 8, s->vlen / 8, data,         \
1479                           fns[s->sew]);                           \
1480        gen_set_label(over);                                       \
1481        return true;                                               \
1482    }                                                              \
1483    return false;                                                  \
1484}
1485GEN_OPIVV_NARROW_TRANS(vnsra_vv)
1486GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
1487
1488static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
1489{
1490    return (vext_check_isa_ill(s) &&
1491            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1492            vext_check_reg(s, a->rd, false) &&
1493            vext_check_reg(s, a->rs2, true) &&
1494            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
1495                2 << s->lmul) &&
1496            (s->lmul < 0x3) && (s->sew < 0x3));
1497}
1498
1499/* OPIVX with NARROW */
1500#define GEN_OPIVX_NARROW_TRANS(NAME)                                     \
1501static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1502{                                                                        \
1503    if (opivx_narrow_check(s, a)) {                                      \
1504        static gen_helper_opivx * const fns[3] = {                       \
1505            gen_helper_##NAME##_b,                                       \
1506            gen_helper_##NAME##_h,                                       \
1507            gen_helper_##NAME##_w,                                       \
1508        };                                                               \
1509        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1510    }                                                                    \
1511    return false;                                                        \
1512}
1513
1514GEN_OPIVX_NARROW_TRANS(vnsra_vx)
1515GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
1516
1517/* OPIVI with NARROW */
1518#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX)                          \
1519static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1520{                                                                        \
1521    if (opivx_narrow_check(s, a)) {                                      \
1522        static gen_helper_opivx * const fns[3] = {                       \
1523            gen_helper_##OPIVX##_b,                                      \
1524            gen_helper_##OPIVX##_h,                                      \
1525            gen_helper_##OPIVX##_w,                                      \
1526        };                                                               \
1527        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1528                           fns[s->sew], s, ZX);                          \
1529    }                                                                    \
1530    return false;                                                        \
1531}
1532
1533GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx)
1534GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx)
1535
1536/* Vector Integer Comparison Instructions */
1537/*
1538 * For all comparison instructions, an illegal instruction exception is raised
1539 * if the destination vector register overlaps a source vector register group
1540 * and LMUL > 1.
1541 */
1542static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1543{
1544    return (vext_check_isa_ill(s) &&
1545            vext_check_reg(s, a->rs2, false) &&
1546            vext_check_reg(s, a->rs1, false) &&
1547            ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
1548              vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
1549             (s->lmul == 0)));
1550}
1551GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1552GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1553GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1554GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1555GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1556GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1557
1558static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1559{
1560    return (vext_check_isa_ill(s) &&
1561            vext_check_reg(s, a->rs2, false) &&
1562            (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
1563             (s->lmul == 0)));
1564}
1565
1566GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1567GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1568GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1569GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1570GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1571GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1572GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1573GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1574
1575GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check)
1576GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check)
1577GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check)
1578GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check)
1579GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check)
1580GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check)
1581
1582/* Vector Integer Min/Max Instructions */
1583GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1584GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1585GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1586GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1587GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1588GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1589GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1590GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1591
1592/* Vector Single-Width Integer Multiply Instructions */
1593GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1594GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1595GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1596GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1597GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1598GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1599GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1600GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1601
1602/* Vector Integer Divide Instructions */
1603GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1604GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1605GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1606GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1607GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1608GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1609GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1610GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1611
1612/* Vector Widening Integer Multiply Instructions */
1613GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1614GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1615GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1616GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1617GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1618GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1619
1620/* Vector Single-Width Integer Multiply-Add Instructions */
1621GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1622GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1623GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1624GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1625GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1626GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1627GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1628GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1629
1630/* Vector Widening Integer Multiply-Add Instructions */
1631GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1632GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1633GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1634GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1635GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1636GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1637GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1638
1639/* Vector Integer Merge and Move Instructions */
1640static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1641{
1642    if (vext_check_isa_ill(s) &&
1643        vext_check_reg(s, a->rd, false) &&
1644        vext_check_reg(s, a->rs1, false)) {
1645
1646        if (s->vl_eq_vlmax) {
1647            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1648                             vreg_ofs(s, a->rs1),
1649                             MAXSZ(s), MAXSZ(s));
1650        } else {
1651            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1652            static gen_helper_gvec_2_ptr * const fns[4] = {
1653                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1654                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1655            };
1656            TCGLabel *over = gen_new_label();
1657            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1658
1659            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1660                               cpu_env, 0, s->vlen / 8, data, fns[s->sew]);
1661            gen_set_label(over);
1662        }
1663        return true;
1664    }
1665    return false;
1666}
1667
1668typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1669static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1670{
1671    if (vext_check_isa_ill(s) &&
1672        vext_check_reg(s, a->rd, false)) {
1673
1674        TCGv s1;
1675        TCGLabel *over = gen_new_label();
1676        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1677
1678        s1 = tcg_temp_new();
1679        gen_get_gpr(s1, a->rs1);
1680
1681        if (s->vl_eq_vlmax) {
1682            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1683                                MAXSZ(s), MAXSZ(s), s1);
1684        } else {
1685            TCGv_i32 desc ;
1686            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1687            TCGv_ptr dest = tcg_temp_new_ptr();
1688            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1689            static gen_helper_vmv_vx * const fns[4] = {
1690                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1691                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1692            };
1693
1694            tcg_gen_ext_tl_i64(s1_i64, s1);
1695            desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1696            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1697            fns[s->sew](dest, s1_i64, cpu_env, desc);
1698
1699            tcg_temp_free_ptr(dest);
1700            tcg_temp_free_i32(desc);
1701            tcg_temp_free_i64(s1_i64);
1702        }
1703
1704        tcg_temp_free(s1);
1705        gen_set_label(over);
1706        return true;
1707    }
1708    return false;
1709}
1710
1711static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
1712{
1713    if (vext_check_isa_ill(s) &&
1714        vext_check_reg(s, a->rd, false)) {
1715
1716        int64_t simm = sextract64(a->rs1, 0, 5);
1717        if (s->vl_eq_vlmax) {
1718            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
1719                                 MAXSZ(s), MAXSZ(s), simm);
1720        } else {
1721            TCGv_i32 desc;
1722            TCGv_i64 s1;
1723            TCGv_ptr dest;
1724            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1725            static gen_helper_vmv_vx * const fns[4] = {
1726                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1727                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1728            };
1729            TCGLabel *over = gen_new_label();
1730            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1731
1732            s1 = tcg_const_i64(simm);
1733            dest = tcg_temp_new_ptr();
1734            desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1735            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1736            fns[s->sew](dest, s1, cpu_env, desc);
1737
1738            tcg_temp_free_ptr(dest);
1739            tcg_temp_free_i32(desc);
1740            tcg_temp_free_i64(s1);
1741            gen_set_label(over);
1742        }
1743        return true;
1744    }
1745    return false;
1746}
1747
1748GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
1749GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
1750GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check)
1751
1752/*
1753 *** Vector Fixed-Point Arithmetic Instructions
1754 */
1755
1756/* Vector Single-Width Saturating Add and Subtract */
1757GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
1758GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
1759GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
1760GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
1761GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
1762GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
1763GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
1764GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
1765GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check)
1766GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check)
1767
1768/* Vector Single-Width Averaging Add and Subtract */
1769GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
1770GEN_OPIVV_TRANS(vasub_vv, opivv_check)
1771GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
1772GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
1773GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
1774
1775/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1776GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
1777GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
1778
1779/* Vector Widening Saturating Scaled Multiply-Add */
1780GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
1781GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
1782GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
1783GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
1784GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
1785GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
1786GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
1787
1788/* Vector Single-Width Scaling Shift Instructions */
1789GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
1790GEN_OPIVV_TRANS(vssra_vv, opivv_check)
1791GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
1792GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
1793GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check)
1794GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check)
1795
1796/* Vector Narrowing Fixed-Point Clip Instructions */
1797GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
1798GEN_OPIVV_NARROW_TRANS(vnclip_vv)
1799GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
1800GEN_OPIVX_NARROW_TRANS(vnclip_vx)
1801GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx)
1802GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx)
1803
1804/*
1805 *** Vector Float Point Arithmetic Instructions
1806 */
1807/* Vector Single-Width Floating-Point Add/Subtract Instructions */
1808
1809/*
1810 * If the current SEW does not correspond to a supported IEEE floating-point
1811 * type, an illegal instruction exception is raised.
1812 */
1813static bool opfvv_check(DisasContext *s, arg_rmrr *a)
1814{
1815    return (vext_check_isa_ill(s) &&
1816            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1817            vext_check_reg(s, a->rd, false) &&
1818            vext_check_reg(s, a->rs2, false) &&
1819            vext_check_reg(s, a->rs1, false) &&
1820            (s->sew != 0));
1821}
1822
1823/* OPFVV without GVEC IR */
1824#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
1825static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1826{                                                                  \
1827    if (CHECK(s, a)) {                                             \
1828        uint32_t data = 0;                                         \
1829        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1830            gen_helper_##NAME##_h,                                 \
1831            gen_helper_##NAME##_w,                                 \
1832            gen_helper_##NAME##_d,                                 \
1833        };                                                         \
1834        TCGLabel *over = gen_new_label();                          \
1835        gen_set_rm(s, 7);                                          \
1836        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1837                                                                   \
1838        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1839        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1840        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1841        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1842                           vreg_ofs(s, a->rs1),                    \
1843                           vreg_ofs(s, a->rs2), cpu_env,           \
1844                           s->vlen / 8, s->vlen / 8, data,         \
1845                           fns[s->sew - 1]);                       \
1846        gen_set_label(over);                                       \
1847        return true;                                               \
1848    }                                                              \
1849    return false;                                                  \
1850}
1851GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
1852GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
1853
1854typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
1855                              TCGv_env, TCGv_i32);
1856
1857static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
1858                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
1859{
1860    TCGv_ptr dest, src2, mask;
1861    TCGv_i32 desc;
1862
1863    TCGLabel *over = gen_new_label();
1864    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1865
1866    dest = tcg_temp_new_ptr();
1867    mask = tcg_temp_new_ptr();
1868    src2 = tcg_temp_new_ptr();
1869    desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1870
1871    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1872    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1873    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1874
1875    fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc);
1876
1877    tcg_temp_free_ptr(dest);
1878    tcg_temp_free_ptr(mask);
1879    tcg_temp_free_ptr(src2);
1880    tcg_temp_free_i32(desc);
1881    gen_set_label(over);
1882    return true;
1883}
1884
1885static bool opfvf_check(DisasContext *s, arg_rmrr *a)
1886{
1887/*
1888 * If the current SEW does not correspond to a supported IEEE floating-point
1889 * type, an illegal instruction exception is raised
1890 */
1891    return (vext_check_isa_ill(s) &&
1892            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1893            vext_check_reg(s, a->rd, false) &&
1894            vext_check_reg(s, a->rs2, false) &&
1895            (s->sew != 0));
1896}
1897
1898/* OPFVF without GVEC IR */
1899#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
1900static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
1901{                                                                 \
1902    if (CHECK(s, a)) {                                            \
1903        uint32_t data = 0;                                        \
1904        static gen_helper_opfvf *const fns[3] = {                 \
1905            gen_helper_##NAME##_h,                                \
1906            gen_helper_##NAME##_w,                                \
1907            gen_helper_##NAME##_d,                                \
1908        };                                                        \
1909        gen_set_rm(s, 7);                                         \
1910        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);            \
1911        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
1912        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
1913        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
1914                           fns[s->sew - 1], s);                   \
1915    }                                                             \
1916    return false;                                                 \
1917}
1918
1919GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
1920GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
1921GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
1922
1923/* Vector Widening Floating-Point Add/Subtract Instructions */
1924static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
1925{
1926    return (vext_check_isa_ill(s) &&
1927            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1928            vext_check_reg(s, a->rd, true) &&
1929            vext_check_reg(s, a->rs2, false) &&
1930            vext_check_reg(s, a->rs1, false) &&
1931            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1932                                     1 << s->lmul) &&
1933            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1934                                     1 << s->lmul) &&
1935            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
1936}
1937
1938/* OPFVV with WIDEN */
1939#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
1940static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
1941{                                                                \
1942    if (CHECK(s, a)) {                                           \
1943        uint32_t data = 0;                                       \
1944        static gen_helper_gvec_4_ptr * const fns[2] = {          \
1945            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
1946        };                                                       \
1947        TCGLabel *over = gen_new_label();                        \
1948        gen_set_rm(s, 7);                                        \
1949        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
1950                                                                 \
1951        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
1952        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
1953        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
1954        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
1955                           vreg_ofs(s, a->rs1),                  \
1956                           vreg_ofs(s, a->rs2), cpu_env,         \
1957                           s->vlen / 8, s->vlen / 8, data,       \
1958                           fns[s->sew - 1]);                     \
1959        gen_set_label(over);                                     \
1960        return true;                                             \
1961    }                                                            \
1962    return false;                                                \
1963}
1964
1965GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
1966GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
1967
1968static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
1969{
1970    return (vext_check_isa_ill(s) &&
1971            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1972            vext_check_reg(s, a->rd, true) &&
1973            vext_check_reg(s, a->rs2, false) &&
1974            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1975                                     1 << s->lmul) &&
1976            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
1977}
1978
1979/* OPFVF with WIDEN */
1980#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
1981static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
1982{                                                                \
1983    if (opfvf_widen_check(s, a)) {                               \
1984        uint32_t data = 0;                                       \
1985        static gen_helper_opfvf *const fns[2] = {                \
1986            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
1987        };                                                       \
1988        gen_set_rm(s, 7);                                        \
1989        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
1990        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
1991        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
1992        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
1993                           fns[s->sew - 1], s);                  \
1994    }                                                            \
1995    return false;                                                \
1996}
1997
1998GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
1999GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2000
2001static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2002{
2003    return (vext_check_isa_ill(s) &&
2004            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2005            vext_check_reg(s, a->rd, true) &&
2006            vext_check_reg(s, a->rs2, true) &&
2007            vext_check_reg(s, a->rs1, false) &&
2008            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
2009                                     1 << s->lmul) &&
2010            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2011}
2012
2013/* WIDEN OPFVV with WIDEN */
2014#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2015static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2016{                                                                  \
2017    if (opfwv_widen_check(s, a)) {                                 \
2018        uint32_t data = 0;                                         \
2019        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2020            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2021        };                                                         \
2022        TCGLabel *over = gen_new_label();                          \
2023        gen_set_rm(s, 7);                                          \
2024        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2025                                                                   \
2026        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2027        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2028        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2029        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2030                           vreg_ofs(s, a->rs1),                    \
2031                           vreg_ofs(s, a->rs2), cpu_env,           \
2032                           s->vlen / 8, s->vlen / 8, data,         \
2033                           fns[s->sew - 1]);                       \
2034        gen_set_label(over);                                       \
2035        return true;                                               \
2036    }                                                              \
2037    return false;                                                  \
2038}
2039
2040GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2041GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2042
2043static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2044{
2045    return (vext_check_isa_ill(s) &&
2046            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2047            vext_check_reg(s, a->rd, true) &&
2048            vext_check_reg(s, a->rs2, true) &&
2049            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2050}
2051
2052/* WIDEN OPFVF with WIDEN */
2053#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2054static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2055{                                                                \
2056    if (opfwf_widen_check(s, a)) {                               \
2057        uint32_t data = 0;                                       \
2058        static gen_helper_opfvf *const fns[2] = {                \
2059            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2060        };                                                       \
2061        gen_set_rm(s, 7);                                        \
2062        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
2063        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2064        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2065        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2066                           fns[s->sew - 1], s);                  \
2067    }                                                            \
2068    return false;                                                \
2069}
2070
2071GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2072GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2073
2074/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2075GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2076GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2077GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2078GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2079GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2080
2081/* Vector Widening Floating-Point Multiply */
2082GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2083GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2084
2085/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2086GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2087GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2088GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2089GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2090GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2091GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2092GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2093GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2094GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2095GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2096GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2097GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2098GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2099GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2100GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2101GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2102
2103/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2104GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2105GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2106GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2107GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2108GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2109GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2110GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2111GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2112
2113/* Vector Floating-Point Square-Root Instruction */
2114
2115/*
2116 * If the current SEW does not correspond to a supported IEEE floating-point
2117 * type, an illegal instruction exception is raised
2118 */
2119static bool opfv_check(DisasContext *s, arg_rmr *a)
2120{
2121   return (vext_check_isa_ill(s) &&
2122            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
2123            vext_check_reg(s, a->rd, false) &&
2124            vext_check_reg(s, a->rs2, false) &&
2125            (s->sew != 0));
2126}
2127
2128#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2129static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2130{                                                                  \
2131    if (CHECK(s, a)) {                                             \
2132        uint32_t data = 0;                                         \
2133        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2134            gen_helper_##NAME##_h,                                 \
2135            gen_helper_##NAME##_w,                                 \
2136            gen_helper_##NAME##_d,                                 \
2137        };                                                         \
2138        TCGLabel *over = gen_new_label();                          \
2139        gen_set_rm(s, 7);                                          \
2140        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2141                                                                   \
2142        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2143        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2144        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2145        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2146                           vreg_ofs(s, a->rs2), cpu_env,           \
2147                           s->vlen / 8, s->vlen / 8, data,         \
2148                           fns[s->sew - 1]);                       \
2149        gen_set_label(over);                                       \
2150        return true;                                               \
2151    }                                                              \
2152    return false;                                                  \
2153}
2154
2155GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2156
2157/* Vector Floating-Point MIN/MAX Instructions */
2158GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2159GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2160GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2161GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2162
2163/* Vector Floating-Point Sign-Injection Instructions */
2164GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2165GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2166GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2167GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2168GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2169GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2170
2171/* Vector Floating-Point Compare Instructions */
2172static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2173{
2174    return (vext_check_isa_ill(s) &&
2175            vext_check_reg(s, a->rs2, false) &&
2176            vext_check_reg(s, a->rs1, false) &&
2177            (s->sew != 0) &&
2178            ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
2179              vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
2180             (s->lmul == 0)));
2181}
2182
2183GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2184GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2185GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2186GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2187GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2188
2189static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2190{
2191    return (vext_check_isa_ill(s) &&
2192            vext_check_reg(s, a->rs2, false) &&
2193            (s->sew != 0) &&
2194            (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
2195             (s->lmul == 0)));
2196}
2197
2198GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2199GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2200GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2201GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2202GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2203GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2204GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2205
2206/* Vector Floating-Point Classify Instruction */
2207GEN_OPFV_TRANS(vfclass_v, opfv_check)
2208
2209/* Vector Floating-Point Merge Instruction */
2210GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2211
2212static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2213{
2214    if (vext_check_isa_ill(s) &&
2215        vext_check_reg(s, a->rd, false) &&
2216        (s->sew != 0)) {
2217
2218        if (s->vl_eq_vlmax) {
2219            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2220                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2221        } else {
2222            TCGv_ptr dest;
2223            TCGv_i32 desc;
2224            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2225            static gen_helper_vmv_vx * const fns[3] = {
2226                gen_helper_vmv_v_x_h,
2227                gen_helper_vmv_v_x_w,
2228                gen_helper_vmv_v_x_d,
2229            };
2230            TCGLabel *over = gen_new_label();
2231            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2232
2233            dest = tcg_temp_new_ptr();
2234            desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2235            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2236            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2237
2238            tcg_temp_free_ptr(dest);
2239            tcg_temp_free_i32(desc);
2240            gen_set_label(over);
2241        }
2242        return true;
2243    }
2244    return false;
2245}
2246
2247/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2248GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2249GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2250GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2251GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2252
2253/* Widening Floating-Point/Integer Type-Convert Instructions */
2254
2255/*
2256 * If the current SEW does not correspond to a supported IEEE floating-point
2257 * type, an illegal instruction exception is raised
2258 */
2259static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2260{
2261    return (vext_check_isa_ill(s) &&
2262            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2263            vext_check_reg(s, a->rd, true) &&
2264            vext_check_reg(s, a->rs2, false) &&
2265            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
2266                                     1 << s->lmul) &&
2267            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2268}
2269
2270#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2271static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2272{                                                                  \
2273    if (opfv_widen_check(s, a)) {                                  \
2274        uint32_t data = 0;                                         \
2275        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2276            gen_helper_##NAME##_h,                                 \
2277            gen_helper_##NAME##_w,                                 \
2278        };                                                         \
2279        TCGLabel *over = gen_new_label();                          \
2280        gen_set_rm(s, 7);                                          \
2281        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2282                                                                   \
2283        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2284        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2285        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2286        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2287                           vreg_ofs(s, a->rs2), cpu_env,           \
2288                           s->vlen / 8, s->vlen / 8, data,         \
2289                           fns[s->sew - 1]);                       \
2290        gen_set_label(over);                                       \
2291        return true;                                               \
2292    }                                                              \
2293    return false;                                                  \
2294}
2295
2296GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2297GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2298GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2299GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2300GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2301
2302/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2303
2304/*
2305 * If the current SEW does not correspond to a supported IEEE floating-point
2306 * type, an illegal instruction exception is raised
2307 */
2308static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2309{
2310    return (vext_check_isa_ill(s) &&
2311            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
2312            vext_check_reg(s, a->rd, false) &&
2313            vext_check_reg(s, a->rs2, true) &&
2314            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
2315                                     2 << s->lmul) &&
2316            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2317}
2318
2319#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2320static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2321{                                                                  \
2322    if (opfv_narrow_check(s, a)) {                                 \
2323        uint32_t data = 0;                                         \
2324        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2325            gen_helper_##NAME##_h,                                 \
2326            gen_helper_##NAME##_w,                                 \
2327        };                                                         \
2328        TCGLabel *over = gen_new_label();                          \
2329        gen_set_rm(s, 7);                                          \
2330        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2331                                                                   \
2332        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2333        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2334        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2335        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2336                           vreg_ofs(s, a->rs2), cpu_env,           \
2337                           s->vlen / 8, s->vlen / 8, data,         \
2338                           fns[s->sew - 1]);                       \
2339        gen_set_label(over);                                       \
2340        return true;                                               \
2341    }                                                              \
2342    return false;                                                  \
2343}
2344
2345GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2346GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2347GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2348GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2349GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2350
2351/*
2352 *** Vector Reduction Operations
2353 */
2354/* Vector Single-Width Integer Reduction Instructions */
2355static bool reduction_check(DisasContext *s, arg_rmrr *a)
2356{
2357    return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false);
2358}
2359
2360GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2361GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2362GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2363GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2364GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2365GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2366GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2367GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2368
2369/* Vector Widening Integer Reduction Instructions */
2370GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check)
2371GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check)
2372
2373/* Vector Single-Width Floating-Point Reduction Instructions */
2374GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2375GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2376GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2377
2378/* Vector Widening Floating-Point Reduction Instructions */
2379GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2380
2381/*
2382 *** Vector Mask Operations
2383 */
2384
2385/* Vector Mask-Register Logical Instructions */
2386#define GEN_MM_TRANS(NAME)                                         \
2387static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2388{                                                                  \
2389    if (vext_check_isa_ill(s)) {                                   \
2390        uint32_t data = 0;                                         \
2391        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2392        TCGLabel *over = gen_new_label();                          \
2393        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2394                                                                   \
2395        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2396        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2397        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2398                           vreg_ofs(s, a->rs1),                    \
2399                           vreg_ofs(s, a->rs2), cpu_env,           \
2400                           s->vlen / 8, s->vlen / 8, data, fn);    \
2401        gen_set_label(over);                                       \
2402        return true;                                               \
2403    }                                                              \
2404    return false;                                                  \
2405}
2406
2407GEN_MM_TRANS(vmand_mm)
2408GEN_MM_TRANS(vmnand_mm)
2409GEN_MM_TRANS(vmandnot_mm)
2410GEN_MM_TRANS(vmxor_mm)
2411GEN_MM_TRANS(vmor_mm)
2412GEN_MM_TRANS(vmnor_mm)
2413GEN_MM_TRANS(vmornot_mm)
2414GEN_MM_TRANS(vmxnor_mm)
2415
2416/* Vector mask population count vmpopc */
2417static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2418{
2419    if (vext_check_isa_ill(s)) {
2420        TCGv_ptr src2, mask;
2421        TCGv dst;
2422        TCGv_i32 desc;
2423        uint32_t data = 0;
2424        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2425        data = FIELD_DP32(data, VDATA, VM, a->vm);
2426        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2427
2428        mask = tcg_temp_new_ptr();
2429        src2 = tcg_temp_new_ptr();
2430        dst = tcg_temp_new();
2431        desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2432
2433        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2434        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2435
2436        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2437        gen_set_gpr(a->rd, dst);
2438
2439        tcg_temp_free_ptr(mask);
2440        tcg_temp_free_ptr(src2);
2441        tcg_temp_free(dst);
2442        tcg_temp_free_i32(desc);
2443        return true;
2444    }
2445    return false;
2446}
2447
2448/* vmfirst find-first-set mask bit */
2449static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2450{
2451    if (vext_check_isa_ill(s)) {
2452        TCGv_ptr src2, mask;
2453        TCGv dst;
2454        TCGv_i32 desc;
2455        uint32_t data = 0;
2456        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2457        data = FIELD_DP32(data, VDATA, VM, a->vm);
2458        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2459
2460        mask = tcg_temp_new_ptr();
2461        src2 = tcg_temp_new_ptr();
2462        dst = tcg_temp_new();
2463        desc = tcg_const_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2464
2465        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2466        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2467
2468        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2469        gen_set_gpr(a->rd, dst);
2470
2471        tcg_temp_free_ptr(mask);
2472        tcg_temp_free_ptr(src2);
2473        tcg_temp_free(dst);
2474        tcg_temp_free_i32(desc);
2475        return true;
2476    }
2477    return false;
2478}
2479
2480/* vmsbf.m set-before-first mask bit */
2481/* vmsif.m set-includ-first mask bit */
2482/* vmsof.m set-only-first mask bit */
2483#define GEN_M_TRANS(NAME)                                          \
2484static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2485{                                                                  \
2486    if (vext_check_isa_ill(s)) {                                   \
2487        uint32_t data = 0;                                         \
2488        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2489        TCGLabel *over = gen_new_label();                          \
2490        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2491                                                                   \
2492        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2493        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2494        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2495        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2496                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2497                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2498                           data, fn);                              \
2499        gen_set_label(over);                                       \
2500        return true;                                               \
2501    }                                                              \
2502    return false;                                                  \
2503}
2504
2505GEN_M_TRANS(vmsbf_m)
2506GEN_M_TRANS(vmsif_m)
2507GEN_M_TRANS(vmsof_m)
2508
2509/* Vector Iota Instruction */
2510static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2511{
2512    if (vext_check_isa_ill(s) &&
2513        vext_check_reg(s, a->rd, false) &&
2514        vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) &&
2515        (a->vm != 0 || a->rd != 0)) {
2516        uint32_t data = 0;
2517        TCGLabel *over = gen_new_label();
2518        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2519
2520        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2521        data = FIELD_DP32(data, VDATA, VM, a->vm);
2522        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2523        static gen_helper_gvec_3_ptr * const fns[4] = {
2524            gen_helper_viota_m_b, gen_helper_viota_m_h,
2525            gen_helper_viota_m_w, gen_helper_viota_m_d,
2526        };
2527        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2528                           vreg_ofs(s, a->rs2), cpu_env,
2529                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2530        gen_set_label(over);
2531        return true;
2532    }
2533    return false;
2534}
2535
2536/* Vector Element Index Instruction */
2537static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2538{
2539    if (vext_check_isa_ill(s) &&
2540        vext_check_reg(s, a->rd, false) &&
2541        vext_check_overlap_mask(s, a->rd, a->vm, false)) {
2542        uint32_t data = 0;
2543        TCGLabel *over = gen_new_label();
2544        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2545
2546        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2547        data = FIELD_DP32(data, VDATA, VM, a->vm);
2548        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2549        static gen_helper_gvec_2_ptr * const fns[4] = {
2550            gen_helper_vid_v_b, gen_helper_vid_v_h,
2551            gen_helper_vid_v_w, gen_helper_vid_v_d,
2552        };
2553        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2554                           cpu_env, s->vlen / 8, s->vlen / 8,
2555                           data, fns[s->sew]);
2556        gen_set_label(over);
2557        return true;
2558    }
2559    return false;
2560}
2561
2562/*
2563 *** Vector Permutation Instructions
2564 */
2565
2566/* Integer Extract Instruction */
2567
2568static void load_element(TCGv_i64 dest, TCGv_ptr base,
2569                         int ofs, int sew)
2570{
2571    switch (sew) {
2572    case MO_8:
2573        tcg_gen_ld8u_i64(dest, base, ofs);
2574        break;
2575    case MO_16:
2576        tcg_gen_ld16u_i64(dest, base, ofs);
2577        break;
2578    case MO_32:
2579        tcg_gen_ld32u_i64(dest, base, ofs);
2580        break;
2581    case MO_64:
2582        tcg_gen_ld_i64(dest, base, ofs);
2583        break;
2584    default:
2585        g_assert_not_reached();
2586        break;
2587    }
2588}
2589
2590/* offset of the idx element with base regsiter r */
2591static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2592{
2593#ifdef HOST_WORDS_BIGENDIAN
2594    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2595#else
2596    return vreg_ofs(s, r) + (idx << s->sew);
2597#endif
2598}
2599
2600/* adjust the index according to the endian */
2601static void endian_adjust(TCGv_i32 ofs, int sew)
2602{
2603#ifdef HOST_WORDS_BIGENDIAN
2604    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2605#endif
2606}
2607
2608/* Load idx >= VLMAX ? 0 : vreg[idx] */
2609static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2610                              int vreg, TCGv idx, int vlmax)
2611{
2612    TCGv_i32 ofs = tcg_temp_new_i32();
2613    TCGv_ptr base = tcg_temp_new_ptr();
2614    TCGv_i64 t_idx = tcg_temp_new_i64();
2615    TCGv_i64 t_vlmax, t_zero;
2616
2617    /*
2618     * Mask the index to the length so that we do
2619     * not produce an out-of-range load.
2620     */
2621    tcg_gen_trunc_tl_i32(ofs, idx);
2622    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2623
2624    /* Convert the index to an offset. */
2625    endian_adjust(ofs, s->sew);
2626    tcg_gen_shli_i32(ofs, ofs, s->sew);
2627
2628    /* Convert the index to a pointer. */
2629    tcg_gen_ext_i32_ptr(base, ofs);
2630    tcg_gen_add_ptr(base, base, cpu_env);
2631
2632    /* Perform the load. */
2633    load_element(dest, base,
2634                 vreg_ofs(s, vreg), s->sew);
2635    tcg_temp_free_ptr(base);
2636    tcg_temp_free_i32(ofs);
2637
2638    /* Flush out-of-range indexing to zero.  */
2639    t_vlmax = tcg_const_i64(vlmax);
2640    t_zero = tcg_const_i64(0);
2641    tcg_gen_extu_tl_i64(t_idx, idx);
2642
2643    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2644                        t_vlmax, dest, t_zero);
2645
2646    tcg_temp_free_i64(t_vlmax);
2647    tcg_temp_free_i64(t_zero);
2648    tcg_temp_free_i64(t_idx);
2649}
2650
2651static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2652                              int vreg, int idx)
2653{
2654    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2655}
2656
2657static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2658{
2659    TCGv_i64 tmp = tcg_temp_new_i64();
2660    TCGv dest = tcg_temp_new();
2661
2662    if (a->rs1 == 0) {
2663        /* Special case vmv.x.s rd, vs2. */
2664        vec_element_loadi(s, tmp, a->rs2, 0);
2665    } else {
2666        /* This instruction ignores LMUL and vector register groups */
2667        int vlmax = s->vlen >> (3 + s->sew);
2668        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2669    }
2670    tcg_gen_trunc_i64_tl(dest, tmp);
2671    gen_set_gpr(a->rd, dest);
2672
2673    tcg_temp_free(dest);
2674    tcg_temp_free_i64(tmp);
2675    return true;
2676}
2677
2678/* Integer Scalar Move Instruction */
2679
2680static void store_element(TCGv_i64 val, TCGv_ptr base,
2681                          int ofs, int sew)
2682{
2683    switch (sew) {
2684    case MO_8:
2685        tcg_gen_st8_i64(val, base, ofs);
2686        break;
2687    case MO_16:
2688        tcg_gen_st16_i64(val, base, ofs);
2689        break;
2690    case MO_32:
2691        tcg_gen_st32_i64(val, base, ofs);
2692        break;
2693    case MO_64:
2694        tcg_gen_st_i64(val, base, ofs);
2695        break;
2696    default:
2697        g_assert_not_reached();
2698        break;
2699    }
2700}
2701
2702/*
2703 * Store vreg[idx] = val.
2704 * The index must be in range of VLMAX.
2705 */
2706static void vec_element_storei(DisasContext *s, int vreg,
2707                               int idx, TCGv_i64 val)
2708{
2709    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2710}
2711
2712/* vmv.s.x vd, rs1 # vd[0] = rs1 */
2713static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
2714{
2715    if (vext_check_isa_ill(s)) {
2716        /* This instruction ignores LMUL and vector register groups */
2717        int maxsz = s->vlen >> 3;
2718        TCGv_i64 t1;
2719        TCGLabel *over = gen_new_label();
2720
2721        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2722        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
2723        if (a->rs1 == 0) {
2724            goto done;
2725        }
2726
2727        t1 = tcg_temp_new_i64();
2728        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
2729        vec_element_storei(s, a->rd, 0, t1);
2730        tcg_temp_free_i64(t1);
2731    done:
2732        gen_set_label(over);
2733        return true;
2734    }
2735    return false;
2736}
2737
2738/* Floating-Point Scalar Move Instructions */
2739static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
2740{
2741    if (!s->vill && has_ext(s, RVF) &&
2742        (s->mstatus_fs != 0) && (s->sew != 0)) {
2743        unsigned int len = 8 << s->sew;
2744
2745        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
2746        if (len < 64) {
2747            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
2748                            MAKE_64BIT_MASK(len, 64 - len));
2749        }
2750
2751        mark_fs_dirty(s);
2752        return true;
2753    }
2754    return false;
2755}
2756
2757/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2758static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
2759{
2760    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
2761        TCGv_i64 t1;
2762        /* The instructions ignore LMUL and vector register group. */
2763        uint32_t vlmax = s->vlen >> 3;
2764
2765        /* if vl == 0, skip vector register write back */
2766        TCGLabel *over = gen_new_label();
2767        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2768
2769        /* zeroed all elements */
2770        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
2771
2772        /* NaN-box f[rs1] as necessary for SEW */
2773        t1 = tcg_temp_new_i64();
2774        if (s->sew == MO_64 && !has_ext(s, RVD)) {
2775            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
2776        } else {
2777            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
2778        }
2779        vec_element_storei(s, a->rd, 0, t1);
2780        tcg_temp_free_i64(t1);
2781        gen_set_label(over);
2782        return true;
2783    }
2784    return false;
2785}
2786
2787/* Vector Slide Instructions */
2788static bool slideup_check(DisasContext *s, arg_rmrr *a)
2789{
2790    return (vext_check_isa_ill(s) &&
2791            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2792            vext_check_reg(s, a->rd, false) &&
2793            vext_check_reg(s, a->rs2, false) &&
2794            (a->rd != a->rs2));
2795}
2796
2797GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
2798GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
2799GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check)
2800
2801GEN_OPIVX_TRANS(vslidedown_vx, opivx_check)
2802GEN_OPIVX_TRANS(vslide1down_vx, opivx_check)
2803GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check)
2804
2805/* Vector Register Gather Instruction */
2806static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
2807{
2808    return (vext_check_isa_ill(s) &&
2809            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2810            vext_check_reg(s, a->rd, false) &&
2811            vext_check_reg(s, a->rs1, false) &&
2812            vext_check_reg(s, a->rs2, false) &&
2813            (a->rd != a->rs2) && (a->rd != a->rs1));
2814}
2815
2816GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
2817
2818static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
2819{
2820    return (vext_check_isa_ill(s) &&
2821            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2822            vext_check_reg(s, a->rd, false) &&
2823            vext_check_reg(s, a->rs2, false) &&
2824            (a->rd != a->rs2));
2825}
2826
2827/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
2828static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
2829{
2830    if (!vrgather_vx_check(s, a)) {
2831        return false;
2832    }
2833
2834    if (a->vm && s->vl_eq_vlmax) {
2835        int vlmax = s->vlen / s->mlen;
2836        TCGv_i64 dest = tcg_temp_new_i64();
2837
2838        if (a->rs1 == 0) {
2839            vec_element_loadi(s, dest, a->rs2, 0);
2840        } else {
2841            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
2842        }
2843
2844        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2845                             MAXSZ(s), MAXSZ(s), dest);
2846        tcg_temp_free_i64(dest);
2847    } else {
2848        static gen_helper_opivx * const fns[4] = {
2849            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
2850            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
2851        };
2852        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
2853    }
2854    return true;
2855}
2856
2857/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
2858static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
2859{
2860    if (!vrgather_vx_check(s, a)) {
2861        return false;
2862    }
2863
2864    if (a->vm && s->vl_eq_vlmax) {
2865        if (a->rs1 >= s->vlen / s->mlen) {
2866            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
2867                                 MAXSZ(s), MAXSZ(s), 0);
2868        } else {
2869            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
2870                                 endian_ofs(s, a->rs2, a->rs1),
2871                                 MAXSZ(s), MAXSZ(s));
2872        }
2873    } else {
2874        static gen_helper_opivx * const fns[4] = {
2875            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
2876            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
2877        };
2878        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1);
2879    }
2880    return true;
2881}
2882
2883/* Vector Compress Instruction */
2884static bool vcompress_vm_check(DisasContext *s, arg_r *a)
2885{
2886    return (vext_check_isa_ill(s) &&
2887            vext_check_reg(s, a->rd, false) &&
2888            vext_check_reg(s, a->rs2, false) &&
2889            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) &&
2890            (a->rd != a->rs2));
2891}
2892
2893static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
2894{
2895    if (vcompress_vm_check(s, a)) {
2896        uint32_t data = 0;
2897        static gen_helper_gvec_4_ptr * const fns[4] = {
2898            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
2899            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
2900        };
2901        TCGLabel *over = gen_new_label();
2902        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2903
2904        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2905        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2906        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2907                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
2908                           cpu_env, s->vlen / 8, s->vlen / 8, data,
2909                           fns[s->sew]);
2910        gen_set_label(over);
2911        return true;
2912    }
2913    return false;
2914}
2915