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