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    REQUIRE_64BIT(s);
747    return amo_check(s, a);
748}
749
750GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check)
751GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check)
752GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check)
753GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check)
754GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check)
755GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check)
756GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check)
757GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check)
758GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check)
759GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64)
760GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64)
761GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64)
762GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64)
763GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64)
764GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64)
765GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64)
766GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64)
767GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64)
768
769/*
770 *** Vector Integer Arithmetic Instructions
771 */
772#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
773
774static bool opivv_check(DisasContext *s, arg_rmrr *a)
775{
776    return (vext_check_isa_ill(s) &&
777            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
778            vext_check_reg(s, a->rd, false) &&
779            vext_check_reg(s, a->rs2, false) &&
780            vext_check_reg(s, a->rs1, false));
781}
782
783typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
784                        uint32_t, uint32_t, uint32_t);
785
786static inline bool
787do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
788              gen_helper_gvec_4_ptr *fn)
789{
790    TCGLabel *over = gen_new_label();
791    if (!opivv_check(s, a)) {
792        return false;
793    }
794
795    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
796
797    if (a->vm && s->vl_eq_vlmax) {
798        gvec_fn(s->sew, vreg_ofs(s, a->rd),
799                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
800                MAXSZ(s), MAXSZ(s));
801    } else {
802        uint32_t data = 0;
803
804        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
805        data = FIELD_DP32(data, VDATA, VM, a->vm);
806        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
807        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
808                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
809                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
810    }
811    gen_set_label(over);
812    return true;
813}
814
815/* OPIVV with GVEC IR */
816#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
817static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
818{                                                                  \
819    static gen_helper_gvec_4_ptr * const fns[4] = {                \
820        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
821        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
822    };                                                             \
823    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
824}
825
826GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
827GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
828
829typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
830                              TCGv_env, TCGv_i32);
831
832static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
833                        gen_helper_opivx *fn, DisasContext *s)
834{
835    TCGv_ptr dest, src2, mask;
836    TCGv src1;
837    TCGv_i32 desc;
838    uint32_t data = 0;
839
840    TCGLabel *over = gen_new_label();
841    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
842
843    dest = tcg_temp_new_ptr();
844    mask = tcg_temp_new_ptr();
845    src2 = tcg_temp_new_ptr();
846    src1 = get_gpr(s, rs1, EXT_NONE);
847
848    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
849    data = FIELD_DP32(data, VDATA, VM, vm);
850    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
851    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
852
853    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
854    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
855    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
856
857    fn(dest, mask, src1, src2, cpu_env, desc);
858
859    tcg_temp_free_ptr(dest);
860    tcg_temp_free_ptr(mask);
861    tcg_temp_free_ptr(src2);
862    gen_set_label(over);
863    return true;
864}
865
866static bool opivx_check(DisasContext *s, arg_rmrr *a)
867{
868    return (vext_check_isa_ill(s) &&
869            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
870            vext_check_reg(s, a->rd, false) &&
871            vext_check_reg(s, a->rs2, false));
872}
873
874typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
875                         uint32_t, uint32_t);
876
877static inline bool
878do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
879              gen_helper_opivx *fn)
880{
881    if (!opivx_check(s, a)) {
882        return false;
883    }
884
885    if (a->vm && s->vl_eq_vlmax) {
886        TCGv_i64 src1 = tcg_temp_new_i64();
887
888        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
889        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
890                src1, MAXSZ(s), MAXSZ(s));
891
892        tcg_temp_free_i64(src1);
893        return true;
894    }
895    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
896}
897
898/* OPIVX with GVEC IR */
899#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
900static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
901{                                                                  \
902    static gen_helper_opivx * const fns[4] = {                     \
903        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
904        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
905    };                                                             \
906    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
907}
908
909GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
910GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
911
912static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
913{
914    tcg_gen_vec_sub8_i64(d, b, a);
915}
916
917static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
918{
919    tcg_gen_vec_sub16_i64(d, b, a);
920}
921
922static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
923{
924    tcg_gen_sub_i32(ret, arg2, arg1);
925}
926
927static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
928{
929    tcg_gen_sub_i64(ret, arg2, arg1);
930}
931
932static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
933{
934    tcg_gen_sub_vec(vece, r, b, a);
935}
936
937static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
938                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
939{
940    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
941    static const GVecGen2s rsub_op[4] = {
942        { .fni8 = gen_vec_rsub8_i64,
943          .fniv = gen_rsub_vec,
944          .fno = gen_helper_vec_rsubs8,
945          .opt_opc = vecop_list,
946          .vece = MO_8 },
947        { .fni8 = gen_vec_rsub16_i64,
948          .fniv = gen_rsub_vec,
949          .fno = gen_helper_vec_rsubs16,
950          .opt_opc = vecop_list,
951          .vece = MO_16 },
952        { .fni4 = gen_rsub_i32,
953          .fniv = gen_rsub_vec,
954          .fno = gen_helper_vec_rsubs32,
955          .opt_opc = vecop_list,
956          .vece = MO_32 },
957        { .fni8 = gen_rsub_i64,
958          .fniv = gen_rsub_vec,
959          .fno = gen_helper_vec_rsubs64,
960          .opt_opc = vecop_list,
961          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
962          .vece = MO_64 },
963    };
964
965    tcg_debug_assert(vece <= MO_64);
966    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
967}
968
969GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
970
971static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
972                        gen_helper_opivx *fn, DisasContext *s, int zx)
973{
974    TCGv_ptr dest, src2, mask;
975    TCGv src1;
976    TCGv_i32 desc;
977    uint32_t data = 0;
978
979    TCGLabel *over = gen_new_label();
980    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
981
982    dest = tcg_temp_new_ptr();
983    mask = tcg_temp_new_ptr();
984    src2 = tcg_temp_new_ptr();
985    if (zx) {
986        src1 = tcg_constant_tl(imm);
987    } else {
988        src1 = tcg_constant_tl(sextract64(imm, 0, 5));
989    }
990    data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
991    data = FIELD_DP32(data, VDATA, VM, vm);
992    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
993    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
994
995    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
996    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
997    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
998
999    fn(dest, mask, src1, src2, cpu_env, desc);
1000
1001    tcg_temp_free_ptr(dest);
1002    tcg_temp_free_ptr(mask);
1003    tcg_temp_free_ptr(src2);
1004    gen_set_label(over);
1005    return true;
1006}
1007
1008typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1009                         uint32_t, uint32_t);
1010
1011static inline bool
1012do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1013              gen_helper_opivx *fn, int zx)
1014{
1015    if (!opivx_check(s, a)) {
1016        return false;
1017    }
1018
1019    if (a->vm && s->vl_eq_vlmax) {
1020        if (zx) {
1021            gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1022                    extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
1023        } else {
1024            gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1025                    sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s));
1026        }
1027    } else {
1028        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx);
1029    }
1030    return true;
1031}
1032
1033/* OPIVI with GVEC IR */
1034#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
1035static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1036{                                                                  \
1037    static gen_helper_opivx * const fns[4] = {                     \
1038        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1039        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1040    };                                                             \
1041    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1042                         fns[s->sew], ZX);                         \
1043}
1044
1045GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi)
1046
1047static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1048                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1049{
1050    TCGv_i64 tmp = tcg_constant_i64(c);
1051    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1052}
1053
1054GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi)
1055
1056/* Vector Widening Integer Add/Subtract */
1057
1058/* OPIVV with WIDEN */
1059static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1060{
1061    return (vext_check_isa_ill(s) &&
1062            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1063            vext_check_reg(s, a->rd, true) &&
1064            vext_check_reg(s, a->rs2, false) &&
1065            vext_check_reg(s, a->rs1, false) &&
1066            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1067                                     1 << s->lmul) &&
1068            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1069                                     1 << s->lmul) &&
1070            (s->lmul < 0x3) && (s->sew < 0x3));
1071}
1072
1073static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1074                           gen_helper_gvec_4_ptr *fn,
1075                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1076{
1077    if (checkfn(s, a)) {
1078        uint32_t data = 0;
1079        TCGLabel *over = gen_new_label();
1080        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1081
1082        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
1083        data = FIELD_DP32(data, VDATA, VM, a->vm);
1084        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1085        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1086                           vreg_ofs(s, a->rs1),
1087                           vreg_ofs(s, a->rs2),
1088                           cpu_env, s->vlen / 8, s->vlen / 8,
1089                           data, fn);
1090        gen_set_label(over);
1091        return true;
1092    }
1093    return false;
1094}
1095
1096#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1097static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1098{                                                            \
1099    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1100        gen_helper_##NAME##_b,                               \
1101        gen_helper_##NAME##_h,                               \
1102        gen_helper_##NAME##_w                                \
1103    };                                                       \
1104    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1105}
1106
1107GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1108GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1109GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1110GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1111
1112/* OPIVX with WIDEN */
1113static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1114{
1115    return (vext_check_isa_ill(s) &&
1116            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1117            vext_check_reg(s, a->rd, true) &&
1118            vext_check_reg(s, a->rs2, false) &&
1119            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1120                                     1 << s->lmul) &&
1121            (s->lmul < 0x3) && (s->sew < 0x3));
1122}
1123
1124static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1125                           gen_helper_opivx *fn)
1126{
1127    if (opivx_widen_check(s, a)) {
1128        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1129    }
1130    return false;
1131}
1132
1133#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1134static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1135{                                                            \
1136    static gen_helper_opivx * const fns[3] = {               \
1137        gen_helper_##NAME##_b,                               \
1138        gen_helper_##NAME##_h,                               \
1139        gen_helper_##NAME##_w                                \
1140    };                                                       \
1141    return do_opivx_widen(s, a, fns[s->sew]);                \
1142}
1143
1144GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1145GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1146GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1147GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1148
1149/* WIDEN OPIVV with WIDEN */
1150static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1151{
1152    return (vext_check_isa_ill(s) &&
1153            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1154            vext_check_reg(s, a->rd, true) &&
1155            vext_check_reg(s, a->rs2, true) &&
1156            vext_check_reg(s, a->rs1, false) &&
1157            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1158                                     1 << s->lmul) &&
1159            (s->lmul < 0x3) && (s->sew < 0x3));
1160}
1161
1162static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1163                           gen_helper_gvec_4_ptr *fn)
1164{
1165    if (opiwv_widen_check(s, a)) {
1166        uint32_t data = 0;
1167        TCGLabel *over = gen_new_label();
1168        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1169
1170        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
1171        data = FIELD_DP32(data, VDATA, VM, a->vm);
1172        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1173        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1174                           vreg_ofs(s, a->rs1),
1175                           vreg_ofs(s, a->rs2),
1176                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1177        gen_set_label(over);
1178        return true;
1179    }
1180    return false;
1181}
1182
1183#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1184static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1185{                                                            \
1186    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1187        gen_helper_##NAME##_b,                               \
1188        gen_helper_##NAME##_h,                               \
1189        gen_helper_##NAME##_w                                \
1190    };                                                       \
1191    return do_opiwv_widen(s, a, fns[s->sew]);                \
1192}
1193
1194GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1195GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1196GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1197GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1198
1199/* WIDEN OPIVX with WIDEN */
1200static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1201{
1202    return (vext_check_isa_ill(s) &&
1203            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1204            vext_check_reg(s, a->rd, true) &&
1205            vext_check_reg(s, a->rs2, true) &&
1206            (s->lmul < 0x3) && (s->sew < 0x3));
1207}
1208
1209static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1210                           gen_helper_opivx *fn)
1211{
1212    if (opiwx_widen_check(s, a)) {
1213        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1214    }
1215    return false;
1216}
1217
1218#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1219static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1220{                                                            \
1221    static gen_helper_opivx * const fns[3] = {               \
1222        gen_helper_##NAME##_b,                               \
1223        gen_helper_##NAME##_h,                               \
1224        gen_helper_##NAME##_w                                \
1225    };                                                       \
1226    return do_opiwx_widen(s, a, fns[s->sew]);                \
1227}
1228
1229GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1230GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1231GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1232GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1233
1234/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1235/* OPIVV without GVEC IR */
1236#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1237static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1238{                                                                  \
1239    if (CHECK(s, a)) {                                             \
1240        uint32_t data = 0;                                         \
1241        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1242            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1243            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1244        };                                                         \
1245        TCGLabel *over = gen_new_label();                          \
1246        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1247                                                                   \
1248        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1249        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1250        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1251        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1252                           vreg_ofs(s, a->rs1),                    \
1253                           vreg_ofs(s, a->rs2), cpu_env,           \
1254                           s->vlen / 8, s->vlen / 8, data,         \
1255                           fns[s->sew]);                           \
1256        gen_set_label(over);                                       \
1257        return true;                                               \
1258    }                                                              \
1259    return false;                                                  \
1260}
1261
1262/*
1263 * For vadc and vsbc, an illegal instruction exception is raised if the
1264 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1265 */
1266static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1267{
1268    return (vext_check_isa_ill(s) &&
1269            vext_check_reg(s, a->rd, false) &&
1270            vext_check_reg(s, a->rs2, false) &&
1271            vext_check_reg(s, a->rs1, false) &&
1272            ((a->rd != 0) || (s->lmul == 0)));
1273}
1274
1275GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1276GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1277
1278/*
1279 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1280 * destination vector register overlaps a source vector register group.
1281 */
1282static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1283{
1284    return (vext_check_isa_ill(s) &&
1285            vext_check_reg(s, a->rs2, false) &&
1286            vext_check_reg(s, a->rs1, false) &&
1287            vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
1288            vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
1289}
1290
1291GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1292GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1293
1294static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1295{
1296    return (vext_check_isa_ill(s) &&
1297            vext_check_reg(s, a->rd, false) &&
1298            vext_check_reg(s, a->rs2, false) &&
1299            ((a->rd != 0) || (s->lmul == 0)));
1300}
1301
1302/* OPIVX without GVEC IR */
1303#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1304static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1305{                                                                        \
1306    if (CHECK(s, a)) {                                                   \
1307        static gen_helper_opivx * const fns[4] = {                       \
1308            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1309            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1310        };                                                               \
1311                                                                         \
1312        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1313    }                                                                    \
1314    return false;                                                        \
1315}
1316
1317GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1318GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1319
1320static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1321{
1322    return (vext_check_isa_ill(s) &&
1323            vext_check_reg(s, a->rs2, false) &&
1324            vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
1325}
1326
1327GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1328GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1329
1330/* OPIVI without GVEC IR */
1331#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK)                          \
1332static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1333{                                                                        \
1334    if (CHECK(s, a)) {                                                   \
1335        static gen_helper_opivx * const fns[4] = {                       \
1336            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1337            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1338        };                                                               \
1339        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1340                           fns[s->sew], s, ZX);                          \
1341    }                                                                    \
1342    return false;                                                        \
1343}
1344
1345GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check)
1346GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check)
1347
1348/* Vector Bitwise Logical Instructions */
1349GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1350GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1351GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1352GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1353GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1354GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1355GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi)
1356GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx,  ori)
1357GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori)
1358
1359/* Vector Single-Width Bit Shift Instructions */
1360GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1361GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1362GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1363
1364typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1365                           uint32_t, uint32_t);
1366
1367static inline bool
1368do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1369                    gen_helper_opivx *fn)
1370{
1371    if (!opivx_check(s, a)) {
1372        return false;
1373    }
1374
1375    if (a->vm && s->vl_eq_vlmax) {
1376        TCGv_i32 src1 = tcg_temp_new_i32();
1377
1378        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1379        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1380        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1381                src1, MAXSZ(s), MAXSZ(s));
1382
1383        tcg_temp_free_i32(src1);
1384        return true;
1385    }
1386    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1387}
1388
1389#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1390static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1391{                                                                         \
1392    static gen_helper_opivx * const fns[4] = {                            \
1393        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1394        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1395    };                                                                    \
1396                                                                          \
1397    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1398}
1399
1400GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1401GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1402GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1403
1404GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx,  shli)
1405GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx,  shri)
1406GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx,  sari)
1407
1408/* Vector Narrowing Integer Right Shift Instructions */
1409static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
1410{
1411    return (vext_check_isa_ill(s) &&
1412            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1413            vext_check_reg(s, a->rd, false) &&
1414            vext_check_reg(s, a->rs2, true) &&
1415            vext_check_reg(s, a->rs1, false) &&
1416            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
1417                2 << s->lmul) &&
1418            (s->lmul < 0x3) && (s->sew < 0x3));
1419}
1420
1421/* OPIVV with NARROW */
1422#define GEN_OPIVV_NARROW_TRANS(NAME)                               \
1423static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1424{                                                                  \
1425    if (opivv_narrow_check(s, a)) {                                \
1426        uint32_t data = 0;                                         \
1427        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1428            gen_helper_##NAME##_b,                                 \
1429            gen_helper_##NAME##_h,                                 \
1430            gen_helper_##NAME##_w,                                 \
1431        };                                                         \
1432        TCGLabel *over = gen_new_label();                          \
1433        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1434                                                                   \
1435        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1436        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1437        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1438        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1439                           vreg_ofs(s, a->rs1),                    \
1440                           vreg_ofs(s, a->rs2), cpu_env,           \
1441                           s->vlen / 8, s->vlen / 8, data,         \
1442                           fns[s->sew]);                           \
1443        gen_set_label(over);                                       \
1444        return true;                                               \
1445    }                                                              \
1446    return false;                                                  \
1447}
1448GEN_OPIVV_NARROW_TRANS(vnsra_vv)
1449GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
1450
1451static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
1452{
1453    return (vext_check_isa_ill(s) &&
1454            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1455            vext_check_reg(s, a->rd, false) &&
1456            vext_check_reg(s, a->rs2, true) &&
1457            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
1458                2 << s->lmul) &&
1459            (s->lmul < 0x3) && (s->sew < 0x3));
1460}
1461
1462/* OPIVX with NARROW */
1463#define GEN_OPIVX_NARROW_TRANS(NAME)                                     \
1464static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1465{                                                                        \
1466    if (opivx_narrow_check(s, a)) {                                      \
1467        static gen_helper_opivx * const fns[3] = {                       \
1468            gen_helper_##NAME##_b,                                       \
1469            gen_helper_##NAME##_h,                                       \
1470            gen_helper_##NAME##_w,                                       \
1471        };                                                               \
1472        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1473    }                                                                    \
1474    return false;                                                        \
1475}
1476
1477GEN_OPIVX_NARROW_TRANS(vnsra_vx)
1478GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
1479
1480/* OPIVI with NARROW */
1481#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX)                          \
1482static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1483{                                                                        \
1484    if (opivx_narrow_check(s, a)) {                                      \
1485        static gen_helper_opivx * const fns[3] = {                       \
1486            gen_helper_##OPIVX##_b,                                      \
1487            gen_helper_##OPIVX##_h,                                      \
1488            gen_helper_##OPIVX##_w,                                      \
1489        };                                                               \
1490        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1491                           fns[s->sew], s, ZX);                          \
1492    }                                                                    \
1493    return false;                                                        \
1494}
1495
1496GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx)
1497GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx)
1498
1499/* Vector Integer Comparison Instructions */
1500/*
1501 * For all comparison instructions, an illegal instruction exception is raised
1502 * if the destination vector register overlaps a source vector register group
1503 * and LMUL > 1.
1504 */
1505static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1506{
1507    return (vext_check_isa_ill(s) &&
1508            vext_check_reg(s, a->rs2, false) &&
1509            vext_check_reg(s, a->rs1, false) &&
1510            ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
1511              vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
1512             (s->lmul == 0)));
1513}
1514GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1515GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1516GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1517GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1518GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1519GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1520
1521static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1522{
1523    return (vext_check_isa_ill(s) &&
1524            vext_check_reg(s, a->rs2, false) &&
1525            (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
1526             (s->lmul == 0)));
1527}
1528
1529GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1530GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1531GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1532GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1533GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1534GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1535GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1536GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1537
1538GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check)
1539GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check)
1540GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check)
1541GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check)
1542GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check)
1543GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check)
1544
1545/* Vector Integer Min/Max Instructions */
1546GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1547GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1548GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1549GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1550GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1551GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1552GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1553GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1554
1555/* Vector Single-Width Integer Multiply Instructions */
1556GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1557GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1558GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1559GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1560GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1561GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1562GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1563GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1564
1565/* Vector Integer Divide Instructions */
1566GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1567GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1568GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1569GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1570GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1571GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1572GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1573GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1574
1575/* Vector Widening Integer Multiply Instructions */
1576GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1577GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1578GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1579GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1580GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1581GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1582
1583/* Vector Single-Width Integer Multiply-Add Instructions */
1584GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1585GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1586GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1587GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1588GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1589GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1590GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1591GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1592
1593/* Vector Widening Integer Multiply-Add Instructions */
1594GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1595GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1596GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1597GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1598GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1599GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1600GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1601
1602/* Vector Integer Merge and Move Instructions */
1603static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1604{
1605    if (vext_check_isa_ill(s) &&
1606        vext_check_reg(s, a->rd, false) &&
1607        vext_check_reg(s, a->rs1, false)) {
1608
1609        if (s->vl_eq_vlmax) {
1610            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1611                             vreg_ofs(s, a->rs1),
1612                             MAXSZ(s), MAXSZ(s));
1613        } else {
1614            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1615            static gen_helper_gvec_2_ptr * const fns[4] = {
1616                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1617                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1618            };
1619            TCGLabel *over = gen_new_label();
1620            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1621
1622            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1623                               cpu_env, s->vlen / 8, s->vlen / 8, data,
1624                               fns[s->sew]);
1625            gen_set_label(over);
1626        }
1627        return true;
1628    }
1629    return false;
1630}
1631
1632typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1633static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1634{
1635    if (vext_check_isa_ill(s) &&
1636        vext_check_reg(s, a->rd, false)) {
1637
1638        TCGv s1;
1639        TCGLabel *over = gen_new_label();
1640        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1641
1642        s1 = get_gpr(s, a->rs1, EXT_SIGN);
1643
1644        if (s->vl_eq_vlmax) {
1645            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1646                                MAXSZ(s), MAXSZ(s), s1);
1647        } else {
1648            TCGv_i32 desc;
1649            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1650            TCGv_ptr dest = tcg_temp_new_ptr();
1651            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1652            static gen_helper_vmv_vx * const fns[4] = {
1653                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1654                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1655            };
1656
1657            tcg_gen_ext_tl_i64(s1_i64, s1);
1658            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1659            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1660            fns[s->sew](dest, s1_i64, cpu_env, desc);
1661
1662            tcg_temp_free_ptr(dest);
1663            tcg_temp_free_i64(s1_i64);
1664        }
1665
1666        gen_set_label(over);
1667        return true;
1668    }
1669    return false;
1670}
1671
1672static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
1673{
1674    if (vext_check_isa_ill(s) &&
1675        vext_check_reg(s, a->rd, false)) {
1676
1677        int64_t simm = sextract64(a->rs1, 0, 5);
1678        if (s->vl_eq_vlmax) {
1679            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
1680                                 MAXSZ(s), MAXSZ(s), simm);
1681        } else {
1682            TCGv_i32 desc;
1683            TCGv_i64 s1;
1684            TCGv_ptr dest;
1685            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1686            static gen_helper_vmv_vx * const fns[4] = {
1687                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1688                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1689            };
1690            TCGLabel *over = gen_new_label();
1691            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1692
1693            s1 = tcg_constant_i64(simm);
1694            dest = tcg_temp_new_ptr();
1695            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1696            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1697            fns[s->sew](dest, s1, cpu_env, desc);
1698
1699            tcg_temp_free_ptr(dest);
1700            gen_set_label(over);
1701        }
1702        return true;
1703    }
1704    return false;
1705}
1706
1707GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
1708GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
1709GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check)
1710
1711/*
1712 *** Vector Fixed-Point Arithmetic Instructions
1713 */
1714
1715/* Vector Single-Width Saturating Add and Subtract */
1716GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
1717GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
1718GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
1719GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
1720GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
1721GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
1722GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
1723GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
1724GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check)
1725GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check)
1726
1727/* Vector Single-Width Averaging Add and Subtract */
1728GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
1729GEN_OPIVV_TRANS(vasub_vv, opivv_check)
1730GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
1731GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
1732GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
1733
1734/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1735GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
1736GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
1737
1738/* Vector Widening Saturating Scaled Multiply-Add */
1739GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
1740GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
1741GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
1742GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
1743GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
1744GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
1745GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
1746
1747/* Vector Single-Width Scaling Shift Instructions */
1748GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
1749GEN_OPIVV_TRANS(vssra_vv, opivv_check)
1750GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
1751GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
1752GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check)
1753GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check)
1754
1755/* Vector Narrowing Fixed-Point Clip Instructions */
1756GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
1757GEN_OPIVV_NARROW_TRANS(vnclip_vv)
1758GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
1759GEN_OPIVX_NARROW_TRANS(vnclip_vx)
1760GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx)
1761GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx)
1762
1763/*
1764 *** Vector Float Point Arithmetic Instructions
1765 */
1766/* Vector Single-Width Floating-Point Add/Subtract Instructions */
1767
1768/*
1769 * If the current SEW does not correspond to a supported IEEE floating-point
1770 * type, an illegal instruction exception is raised.
1771 */
1772static bool opfvv_check(DisasContext *s, arg_rmrr *a)
1773{
1774    return (vext_check_isa_ill(s) &&
1775            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1776            vext_check_reg(s, a->rd, false) &&
1777            vext_check_reg(s, a->rs2, false) &&
1778            vext_check_reg(s, a->rs1, false) &&
1779            (s->sew != 0));
1780}
1781
1782/* OPFVV without GVEC IR */
1783#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
1784static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1785{                                                                  \
1786    if (CHECK(s, a)) {                                             \
1787        uint32_t data = 0;                                         \
1788        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1789            gen_helper_##NAME##_h,                                 \
1790            gen_helper_##NAME##_w,                                 \
1791            gen_helper_##NAME##_d,                                 \
1792        };                                                         \
1793        TCGLabel *over = gen_new_label();                          \
1794        gen_set_rm(s, 7);                                          \
1795        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1796                                                                   \
1797        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1798        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1799        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1800        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1801                           vreg_ofs(s, a->rs1),                    \
1802                           vreg_ofs(s, a->rs2), cpu_env,           \
1803                           s->vlen / 8, s->vlen / 8, data,         \
1804                           fns[s->sew - 1]);                       \
1805        gen_set_label(over);                                       \
1806        return true;                                               \
1807    }                                                              \
1808    return false;                                                  \
1809}
1810GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
1811GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
1812
1813typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
1814                              TCGv_env, TCGv_i32);
1815
1816static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
1817                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
1818{
1819    TCGv_ptr dest, src2, mask;
1820    TCGv_i32 desc;
1821
1822    TCGLabel *over = gen_new_label();
1823    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1824
1825    dest = tcg_temp_new_ptr();
1826    mask = tcg_temp_new_ptr();
1827    src2 = tcg_temp_new_ptr();
1828    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1829
1830    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1831    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1832    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1833
1834    fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc);
1835
1836    tcg_temp_free_ptr(dest);
1837    tcg_temp_free_ptr(mask);
1838    tcg_temp_free_ptr(src2);
1839    gen_set_label(over);
1840    return true;
1841}
1842
1843static bool opfvf_check(DisasContext *s, arg_rmrr *a)
1844{
1845/*
1846 * If the current SEW does not correspond to a supported IEEE floating-point
1847 * type, an illegal instruction exception is raised
1848 */
1849    return (vext_check_isa_ill(s) &&
1850            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
1851            vext_check_reg(s, a->rd, false) &&
1852            vext_check_reg(s, a->rs2, false) &&
1853            (s->sew != 0));
1854}
1855
1856/* OPFVF without GVEC IR */
1857#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
1858static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
1859{                                                                 \
1860    if (CHECK(s, a)) {                                            \
1861        uint32_t data = 0;                                        \
1862        static gen_helper_opfvf *const fns[3] = {                 \
1863            gen_helper_##NAME##_h,                                \
1864            gen_helper_##NAME##_w,                                \
1865            gen_helper_##NAME##_d,                                \
1866        };                                                        \
1867        gen_set_rm(s, 7);                                         \
1868        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);            \
1869        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
1870        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
1871        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
1872                           fns[s->sew - 1], s);                   \
1873    }                                                             \
1874    return false;                                                 \
1875}
1876
1877GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
1878GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
1879GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
1880
1881/* Vector Widening Floating-Point Add/Subtract Instructions */
1882static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
1883{
1884    return (vext_check_isa_ill(s) &&
1885            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1886            vext_check_reg(s, a->rd, true) &&
1887            vext_check_reg(s, a->rs2, false) &&
1888            vext_check_reg(s, a->rs1, false) &&
1889            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1890                                     1 << s->lmul) &&
1891            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1892                                     1 << s->lmul) &&
1893            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
1894}
1895
1896/* OPFVV with WIDEN */
1897#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
1898static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
1899{                                                                \
1900    if (CHECK(s, a)) {                                           \
1901        uint32_t data = 0;                                       \
1902        static gen_helper_gvec_4_ptr * const fns[2] = {          \
1903            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
1904        };                                                       \
1905        TCGLabel *over = gen_new_label();                        \
1906        gen_set_rm(s, 7);                                        \
1907        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
1908                                                                 \
1909        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
1910        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
1911        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
1912        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
1913                           vreg_ofs(s, a->rs1),                  \
1914                           vreg_ofs(s, a->rs2), cpu_env,         \
1915                           s->vlen / 8, s->vlen / 8, data,       \
1916                           fns[s->sew - 1]);                     \
1917        gen_set_label(over);                                     \
1918        return true;                                             \
1919    }                                                            \
1920    return false;                                                \
1921}
1922
1923GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
1924GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
1925
1926static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
1927{
1928    return (vext_check_isa_ill(s) &&
1929            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1930            vext_check_reg(s, a->rd, true) &&
1931            vext_check_reg(s, a->rs2, false) &&
1932            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
1933                                     1 << s->lmul) &&
1934            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
1935}
1936
1937/* OPFVF with WIDEN */
1938#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
1939static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
1940{                                                                \
1941    if (opfvf_widen_check(s, a)) {                               \
1942        uint32_t data = 0;                                       \
1943        static gen_helper_opfvf *const fns[2] = {                \
1944            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
1945        };                                                       \
1946        gen_set_rm(s, 7);                                        \
1947        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
1948        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
1949        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
1950        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
1951                           fns[s->sew - 1], s);                  \
1952    }                                                            \
1953    return false;                                                \
1954}
1955
1956GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
1957GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
1958
1959static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
1960{
1961    return (vext_check_isa_ill(s) &&
1962            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
1963            vext_check_reg(s, a->rd, true) &&
1964            vext_check_reg(s, a->rs2, true) &&
1965            vext_check_reg(s, a->rs1, false) &&
1966            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1,
1967                                     1 << s->lmul) &&
1968            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
1969}
1970
1971/* WIDEN OPFVV with WIDEN */
1972#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
1973static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1974{                                                                  \
1975    if (opfwv_widen_check(s, a)) {                                 \
1976        uint32_t data = 0;                                         \
1977        static gen_helper_gvec_4_ptr * const fns[2] = {            \
1978            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
1979        };                                                         \
1980        TCGLabel *over = gen_new_label();                          \
1981        gen_set_rm(s, 7);                                          \
1982        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1983                                                                   \
1984        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
1985        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1986        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1987        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1988                           vreg_ofs(s, a->rs1),                    \
1989                           vreg_ofs(s, a->rs2), cpu_env,           \
1990                           s->vlen / 8, s->vlen / 8, data,         \
1991                           fns[s->sew - 1]);                       \
1992        gen_set_label(over);                                       \
1993        return true;                                               \
1994    }                                                              \
1995    return false;                                                  \
1996}
1997
1998GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
1999GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2000
2001static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2002{
2003    return (vext_check_isa_ill(s) &&
2004            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2005            vext_check_reg(s, a->rd, true) &&
2006            vext_check_reg(s, a->rs2, true) &&
2007            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2008}
2009
2010/* WIDEN OPFVF with WIDEN */
2011#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2012static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2013{                                                                \
2014    if (opfwf_widen_check(s, a)) {                               \
2015        uint32_t data = 0;                                       \
2016        static gen_helper_opfvf *const fns[2] = {                \
2017            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2018        };                                                       \
2019        gen_set_rm(s, 7);                                        \
2020        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);           \
2021        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2022        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2023        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2024                           fns[s->sew - 1], s);                  \
2025    }                                                            \
2026    return false;                                                \
2027}
2028
2029GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2030GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2031
2032/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2033GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2034GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2035GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2036GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2037GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2038
2039/* Vector Widening Floating-Point Multiply */
2040GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2041GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2042
2043/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2044GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2045GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2046GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2047GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2048GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2049GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2050GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2051GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2052GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2053GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2054GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2055GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2056GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2057GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2058GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2059GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2060
2061/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2062GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2063GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2064GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2065GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2066GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2067GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2068GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2069GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2070
2071/* Vector Floating-Point Square-Root Instruction */
2072
2073/*
2074 * If the current SEW does not correspond to a supported IEEE floating-point
2075 * type, an illegal instruction exception is raised
2076 */
2077static bool opfv_check(DisasContext *s, arg_rmr *a)
2078{
2079   return (vext_check_isa_ill(s) &&
2080            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
2081            vext_check_reg(s, a->rd, false) &&
2082            vext_check_reg(s, a->rs2, false) &&
2083            (s->sew != 0));
2084}
2085
2086#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2087static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2088{                                                                  \
2089    if (CHECK(s, a)) {                                             \
2090        uint32_t data = 0;                                         \
2091        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2092            gen_helper_##NAME##_h,                                 \
2093            gen_helper_##NAME##_w,                                 \
2094            gen_helper_##NAME##_d,                                 \
2095        };                                                         \
2096        TCGLabel *over = gen_new_label();                          \
2097        gen_set_rm(s, 7);                                          \
2098        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2099                                                                   \
2100        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2101        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2102        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2103        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2104                           vreg_ofs(s, a->rs2), cpu_env,           \
2105                           s->vlen / 8, s->vlen / 8, data,         \
2106                           fns[s->sew - 1]);                       \
2107        gen_set_label(over);                                       \
2108        return true;                                               \
2109    }                                                              \
2110    return false;                                                  \
2111}
2112
2113GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2114
2115/* Vector Floating-Point MIN/MAX Instructions */
2116GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2117GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2118GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2119GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2120
2121/* Vector Floating-Point Sign-Injection Instructions */
2122GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2123GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2124GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2125GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2126GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2127GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2128
2129/* Vector Floating-Point Compare Instructions */
2130static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2131{
2132    return (vext_check_isa_ill(s) &&
2133            vext_check_reg(s, a->rs2, false) &&
2134            vext_check_reg(s, a->rs1, false) &&
2135            (s->sew != 0) &&
2136            ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
2137              vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) ||
2138             (s->lmul == 0)));
2139}
2140
2141GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2142GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2143GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2144GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2145GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2146
2147static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2148{
2149    return (vext_check_isa_ill(s) &&
2150            vext_check_reg(s, a->rs2, false) &&
2151            (s->sew != 0) &&
2152            (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) ||
2153             (s->lmul == 0)));
2154}
2155
2156GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2157GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2158GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2159GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2160GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2161GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2162GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2163
2164/* Vector Floating-Point Classify Instruction */
2165GEN_OPFV_TRANS(vfclass_v, opfv_check)
2166
2167/* Vector Floating-Point Merge Instruction */
2168GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2169
2170static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2171{
2172    if (vext_check_isa_ill(s) &&
2173        vext_check_reg(s, a->rd, false) &&
2174        (s->sew != 0)) {
2175
2176        if (s->vl_eq_vlmax) {
2177            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2178                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2179        } else {
2180            TCGv_ptr dest;
2181            TCGv_i32 desc;
2182            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2183            static gen_helper_vmv_vx * const fns[3] = {
2184                gen_helper_vmv_v_x_h,
2185                gen_helper_vmv_v_x_w,
2186                gen_helper_vmv_v_x_d,
2187            };
2188            TCGLabel *over = gen_new_label();
2189            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2190
2191            dest = tcg_temp_new_ptr();
2192            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2193            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2194            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2195
2196            tcg_temp_free_ptr(dest);
2197            gen_set_label(over);
2198        }
2199        return true;
2200    }
2201    return false;
2202}
2203
2204/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2205GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2206GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2207GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2208GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2209
2210/* Widening Floating-Point/Integer Type-Convert Instructions */
2211
2212/*
2213 * If the current SEW does not correspond to a supported IEEE floating-point
2214 * type, an illegal instruction exception is raised
2215 */
2216static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2217{
2218    return (vext_check_isa_ill(s) &&
2219            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2220            vext_check_reg(s, a->rd, true) &&
2221            vext_check_reg(s, a->rs2, false) &&
2222            vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2,
2223                                     1 << s->lmul) &&
2224            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2225}
2226
2227#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2228static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2229{                                                                  \
2230    if (opfv_widen_check(s, a)) {                                  \
2231        uint32_t data = 0;                                         \
2232        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2233            gen_helper_##NAME##_h,                                 \
2234            gen_helper_##NAME##_w,                                 \
2235        };                                                         \
2236        TCGLabel *over = gen_new_label();                          \
2237        gen_set_rm(s, 7);                                          \
2238        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2239                                                                   \
2240        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2241        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2242        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2243        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2244                           vreg_ofs(s, a->rs2), cpu_env,           \
2245                           s->vlen / 8, s->vlen / 8, data,         \
2246                           fns[s->sew - 1]);                       \
2247        gen_set_label(over);                                       \
2248        return true;                                               \
2249    }                                                              \
2250    return false;                                                  \
2251}
2252
2253GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2254GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2255GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2256GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2257GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2258
2259/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2260
2261/*
2262 * If the current SEW does not correspond to a supported IEEE floating-point
2263 * type, an illegal instruction exception is raised
2264 */
2265static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2266{
2267    return (vext_check_isa_ill(s) &&
2268            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
2269            vext_check_reg(s, a->rd, false) &&
2270            vext_check_reg(s, a->rs2, true) &&
2271            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2,
2272                                     2 << s->lmul) &&
2273            (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0));
2274}
2275
2276#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2277static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2278{                                                                  \
2279    if (opfv_narrow_check(s, a)) {                                 \
2280        uint32_t data = 0;                                         \
2281        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2282            gen_helper_##NAME##_h,                                 \
2283            gen_helper_##NAME##_w,                                 \
2284        };                                                         \
2285        TCGLabel *over = gen_new_label();                          \
2286        gen_set_rm(s, 7);                                          \
2287        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2288                                                                   \
2289        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2290        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2291        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2292        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2293                           vreg_ofs(s, a->rs2), cpu_env,           \
2294                           s->vlen / 8, s->vlen / 8, data,         \
2295                           fns[s->sew - 1]);                       \
2296        gen_set_label(over);                                       \
2297        return true;                                               \
2298    }                                                              \
2299    return false;                                                  \
2300}
2301
2302GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2303GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2304GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2305GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2306GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2307
2308/*
2309 *** Vector Reduction Operations
2310 */
2311/* Vector Single-Width Integer Reduction Instructions */
2312static bool reduction_check(DisasContext *s, arg_rmrr *a)
2313{
2314    return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false);
2315}
2316
2317GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2318GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2319GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2320GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2321GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2322GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2323GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2324GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2325
2326/* Vector Widening Integer Reduction Instructions */
2327GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check)
2328GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check)
2329
2330/* Vector Single-Width Floating-Point Reduction Instructions */
2331GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2332GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2333GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2334
2335/* Vector Widening Floating-Point Reduction Instructions */
2336GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2337
2338/*
2339 *** Vector Mask Operations
2340 */
2341
2342/* Vector Mask-Register Logical Instructions */
2343#define GEN_MM_TRANS(NAME)                                         \
2344static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2345{                                                                  \
2346    if (vext_check_isa_ill(s)) {                                   \
2347        uint32_t data = 0;                                         \
2348        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2349        TCGLabel *over = gen_new_label();                          \
2350        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2351                                                                   \
2352        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2353        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2354        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2355                           vreg_ofs(s, a->rs1),                    \
2356                           vreg_ofs(s, a->rs2), cpu_env,           \
2357                           s->vlen / 8, s->vlen / 8, data, fn);    \
2358        gen_set_label(over);                                       \
2359        return true;                                               \
2360    }                                                              \
2361    return false;                                                  \
2362}
2363
2364GEN_MM_TRANS(vmand_mm)
2365GEN_MM_TRANS(vmnand_mm)
2366GEN_MM_TRANS(vmandnot_mm)
2367GEN_MM_TRANS(vmxor_mm)
2368GEN_MM_TRANS(vmor_mm)
2369GEN_MM_TRANS(vmnor_mm)
2370GEN_MM_TRANS(vmornot_mm)
2371GEN_MM_TRANS(vmxnor_mm)
2372
2373/* Vector mask population count vmpopc */
2374static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2375{
2376    if (vext_check_isa_ill(s)) {
2377        TCGv_ptr src2, mask;
2378        TCGv dst;
2379        TCGv_i32 desc;
2380        uint32_t data = 0;
2381        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2382        data = FIELD_DP32(data, VDATA, VM, a->vm);
2383        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2384
2385        mask = tcg_temp_new_ptr();
2386        src2 = tcg_temp_new_ptr();
2387        dst = dest_gpr(s, a->rd);
2388        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2389
2390        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2391        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2392
2393        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2394        gen_set_gpr(s, a->rd, dst);
2395
2396        tcg_temp_free_ptr(mask);
2397        tcg_temp_free_ptr(src2);
2398        return true;
2399    }
2400    return false;
2401}
2402
2403/* vmfirst find-first-set mask bit */
2404static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2405{
2406    if (vext_check_isa_ill(s)) {
2407        TCGv_ptr src2, mask;
2408        TCGv dst;
2409        TCGv_i32 desc;
2410        uint32_t data = 0;
2411        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2412        data = FIELD_DP32(data, VDATA, VM, a->vm);
2413        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2414
2415        mask = tcg_temp_new_ptr();
2416        src2 = tcg_temp_new_ptr();
2417        dst = dest_gpr(s, a->rd);
2418        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2419
2420        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2421        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2422
2423        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2424        gen_set_gpr(s, a->rd, dst);
2425
2426        tcg_temp_free_ptr(mask);
2427        tcg_temp_free_ptr(src2);
2428        return true;
2429    }
2430    return false;
2431}
2432
2433/* vmsbf.m set-before-first mask bit */
2434/* vmsif.m set-includ-first mask bit */
2435/* vmsof.m set-only-first mask bit */
2436#define GEN_M_TRANS(NAME)                                          \
2437static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2438{                                                                  \
2439    if (vext_check_isa_ill(s)) {                                   \
2440        uint32_t data = 0;                                         \
2441        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2442        TCGLabel *over = gen_new_label();                          \
2443        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2444                                                                   \
2445        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);             \
2446        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2447        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2448        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2449                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2450                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2451                           data, fn);                              \
2452        gen_set_label(over);                                       \
2453        return true;                                               \
2454    }                                                              \
2455    return false;                                                  \
2456}
2457
2458GEN_M_TRANS(vmsbf_m)
2459GEN_M_TRANS(vmsif_m)
2460GEN_M_TRANS(vmsof_m)
2461
2462/* Vector Iota Instruction */
2463static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2464{
2465    if (vext_check_isa_ill(s) &&
2466        vext_check_reg(s, a->rd, false) &&
2467        vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) &&
2468        (a->vm != 0 || a->rd != 0)) {
2469        uint32_t data = 0;
2470        TCGLabel *over = gen_new_label();
2471        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2472
2473        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2474        data = FIELD_DP32(data, VDATA, VM, a->vm);
2475        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2476        static gen_helper_gvec_3_ptr * const fns[4] = {
2477            gen_helper_viota_m_b, gen_helper_viota_m_h,
2478            gen_helper_viota_m_w, gen_helper_viota_m_d,
2479        };
2480        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2481                           vreg_ofs(s, a->rs2), cpu_env,
2482                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2483        gen_set_label(over);
2484        return true;
2485    }
2486    return false;
2487}
2488
2489/* Vector Element Index Instruction */
2490static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2491{
2492    if (vext_check_isa_ill(s) &&
2493        vext_check_reg(s, a->rd, false) &&
2494        vext_check_overlap_mask(s, a->rd, a->vm, false)) {
2495        uint32_t data = 0;
2496        TCGLabel *over = gen_new_label();
2497        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2498
2499        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2500        data = FIELD_DP32(data, VDATA, VM, a->vm);
2501        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2502        static gen_helper_gvec_2_ptr * const fns[4] = {
2503            gen_helper_vid_v_b, gen_helper_vid_v_h,
2504            gen_helper_vid_v_w, gen_helper_vid_v_d,
2505        };
2506        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2507                           cpu_env, s->vlen / 8, s->vlen / 8,
2508                           data, fns[s->sew]);
2509        gen_set_label(over);
2510        return true;
2511    }
2512    return false;
2513}
2514
2515/*
2516 *** Vector Permutation Instructions
2517 */
2518
2519/* Integer Extract Instruction */
2520
2521static void load_element(TCGv_i64 dest, TCGv_ptr base,
2522                         int ofs, int sew)
2523{
2524    switch (sew) {
2525    case MO_8:
2526        tcg_gen_ld8u_i64(dest, base, ofs);
2527        break;
2528    case MO_16:
2529        tcg_gen_ld16u_i64(dest, base, ofs);
2530        break;
2531    case MO_32:
2532        tcg_gen_ld32u_i64(dest, base, ofs);
2533        break;
2534    case MO_64:
2535        tcg_gen_ld_i64(dest, base, ofs);
2536        break;
2537    default:
2538        g_assert_not_reached();
2539        break;
2540    }
2541}
2542
2543/* offset of the idx element with base regsiter r */
2544static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2545{
2546#ifdef HOST_WORDS_BIGENDIAN
2547    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2548#else
2549    return vreg_ofs(s, r) + (idx << s->sew);
2550#endif
2551}
2552
2553/* adjust the index according to the endian */
2554static void endian_adjust(TCGv_i32 ofs, int sew)
2555{
2556#ifdef HOST_WORDS_BIGENDIAN
2557    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2558#endif
2559}
2560
2561/* Load idx >= VLMAX ? 0 : vreg[idx] */
2562static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2563                              int vreg, TCGv idx, int vlmax)
2564{
2565    TCGv_i32 ofs = tcg_temp_new_i32();
2566    TCGv_ptr base = tcg_temp_new_ptr();
2567    TCGv_i64 t_idx = tcg_temp_new_i64();
2568    TCGv_i64 t_vlmax, t_zero;
2569
2570    /*
2571     * Mask the index to the length so that we do
2572     * not produce an out-of-range load.
2573     */
2574    tcg_gen_trunc_tl_i32(ofs, idx);
2575    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2576
2577    /* Convert the index to an offset. */
2578    endian_adjust(ofs, s->sew);
2579    tcg_gen_shli_i32(ofs, ofs, s->sew);
2580
2581    /* Convert the index to a pointer. */
2582    tcg_gen_ext_i32_ptr(base, ofs);
2583    tcg_gen_add_ptr(base, base, cpu_env);
2584
2585    /* Perform the load. */
2586    load_element(dest, base,
2587                 vreg_ofs(s, vreg), s->sew);
2588    tcg_temp_free_ptr(base);
2589    tcg_temp_free_i32(ofs);
2590
2591    /* Flush out-of-range indexing to zero.  */
2592    t_vlmax = tcg_constant_i64(vlmax);
2593    t_zero = tcg_constant_i64(0);
2594    tcg_gen_extu_tl_i64(t_idx, idx);
2595
2596    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2597                        t_vlmax, dest, t_zero);
2598
2599    tcg_temp_free_i64(t_idx);
2600}
2601
2602static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2603                              int vreg, int idx)
2604{
2605    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2606}
2607
2608static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2609{
2610    TCGv_i64 tmp = tcg_temp_new_i64();
2611    TCGv dest = dest_gpr(s, a->rd);
2612
2613    if (a->rs1 == 0) {
2614        /* Special case vmv.x.s rd, vs2. */
2615        vec_element_loadi(s, tmp, a->rs2, 0);
2616    } else {
2617        /* This instruction ignores LMUL and vector register groups */
2618        int vlmax = s->vlen >> (3 + s->sew);
2619        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2620    }
2621
2622    tcg_gen_trunc_i64_tl(dest, tmp);
2623    gen_set_gpr(s, a->rd, dest);
2624
2625    tcg_temp_free_i64(tmp);
2626    return true;
2627}
2628
2629/* Integer Scalar Move Instruction */
2630
2631static void store_element(TCGv_i64 val, TCGv_ptr base,
2632                          int ofs, int sew)
2633{
2634    switch (sew) {
2635    case MO_8:
2636        tcg_gen_st8_i64(val, base, ofs);
2637        break;
2638    case MO_16:
2639        tcg_gen_st16_i64(val, base, ofs);
2640        break;
2641    case MO_32:
2642        tcg_gen_st32_i64(val, base, ofs);
2643        break;
2644    case MO_64:
2645        tcg_gen_st_i64(val, base, ofs);
2646        break;
2647    default:
2648        g_assert_not_reached();
2649        break;
2650    }
2651}
2652
2653/*
2654 * Store vreg[idx] = val.
2655 * The index must be in range of VLMAX.
2656 */
2657static void vec_element_storei(DisasContext *s, int vreg,
2658                               int idx, TCGv_i64 val)
2659{
2660    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2661}
2662
2663/* vmv.s.x vd, rs1 # vd[0] = rs1 */
2664static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
2665{
2666    if (vext_check_isa_ill(s)) {
2667        /* This instruction ignores LMUL and vector register groups */
2668        int maxsz = s->vlen >> 3;
2669        TCGv_i64 t1;
2670        TCGLabel *over = gen_new_label();
2671
2672        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2673        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
2674        if (a->rs1 == 0) {
2675            goto done;
2676        }
2677
2678        t1 = tcg_temp_new_i64();
2679        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
2680        vec_element_storei(s, a->rd, 0, t1);
2681        tcg_temp_free_i64(t1);
2682    done:
2683        gen_set_label(over);
2684        return true;
2685    }
2686    return false;
2687}
2688
2689/* Floating-Point Scalar Move Instructions */
2690static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
2691{
2692    if (!s->vill && has_ext(s, RVF) &&
2693        (s->mstatus_fs != 0) && (s->sew != 0)) {
2694        unsigned int len = 8 << s->sew;
2695
2696        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
2697        if (len < 64) {
2698            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
2699                            MAKE_64BIT_MASK(len, 64 - len));
2700        }
2701
2702        mark_fs_dirty(s);
2703        return true;
2704    }
2705    return false;
2706}
2707
2708/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2709static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
2710{
2711    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
2712        TCGv_i64 t1;
2713        /* The instructions ignore LMUL and vector register group. */
2714        uint32_t vlmax = s->vlen >> 3;
2715
2716        /* if vl == 0, skip vector register write back */
2717        TCGLabel *over = gen_new_label();
2718        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2719
2720        /* zeroed all elements */
2721        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
2722
2723        /* NaN-box f[rs1] as necessary for SEW */
2724        t1 = tcg_temp_new_i64();
2725        if (s->sew == MO_64 && !has_ext(s, RVD)) {
2726            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
2727        } else {
2728            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
2729        }
2730        vec_element_storei(s, a->rd, 0, t1);
2731        tcg_temp_free_i64(t1);
2732        gen_set_label(over);
2733        return true;
2734    }
2735    return false;
2736}
2737
2738/* Vector Slide Instructions */
2739static bool slideup_check(DisasContext *s, arg_rmrr *a)
2740{
2741    return (vext_check_isa_ill(s) &&
2742            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2743            vext_check_reg(s, a->rd, false) &&
2744            vext_check_reg(s, a->rs2, false) &&
2745            (a->rd != a->rs2));
2746}
2747
2748GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
2749GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
2750GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check)
2751
2752GEN_OPIVX_TRANS(vslidedown_vx, opivx_check)
2753GEN_OPIVX_TRANS(vslide1down_vx, opivx_check)
2754GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check)
2755
2756/* Vector Register Gather Instruction */
2757static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
2758{
2759    return (vext_check_isa_ill(s) &&
2760            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2761            vext_check_reg(s, a->rd, false) &&
2762            vext_check_reg(s, a->rs1, false) &&
2763            vext_check_reg(s, a->rs2, false) &&
2764            (a->rd != a->rs2) && (a->rd != a->rs1));
2765}
2766
2767GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
2768
2769static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
2770{
2771    return (vext_check_isa_ill(s) &&
2772            vext_check_overlap_mask(s, a->rd, a->vm, true) &&
2773            vext_check_reg(s, a->rd, false) &&
2774            vext_check_reg(s, a->rs2, false) &&
2775            (a->rd != a->rs2));
2776}
2777
2778/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
2779static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
2780{
2781    if (!vrgather_vx_check(s, a)) {
2782        return false;
2783    }
2784
2785    if (a->vm && s->vl_eq_vlmax) {
2786        int vlmax = s->vlen / s->mlen;
2787        TCGv_i64 dest = tcg_temp_new_i64();
2788
2789        if (a->rs1 == 0) {
2790            vec_element_loadi(s, dest, a->rs2, 0);
2791        } else {
2792            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
2793        }
2794
2795        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2796                             MAXSZ(s), MAXSZ(s), dest);
2797        tcg_temp_free_i64(dest);
2798    } else {
2799        static gen_helper_opivx * const fns[4] = {
2800            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
2801            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
2802        };
2803        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
2804    }
2805    return true;
2806}
2807
2808/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
2809static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
2810{
2811    if (!vrgather_vx_check(s, a)) {
2812        return false;
2813    }
2814
2815    if (a->vm && s->vl_eq_vlmax) {
2816        if (a->rs1 >= s->vlen / s->mlen) {
2817            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
2818                                 MAXSZ(s), MAXSZ(s), 0);
2819        } else {
2820            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
2821                                 endian_ofs(s, a->rs2, a->rs1),
2822                                 MAXSZ(s), MAXSZ(s));
2823        }
2824    } else {
2825        static gen_helper_opivx * const fns[4] = {
2826            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
2827            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
2828        };
2829        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1);
2830    }
2831    return true;
2832}
2833
2834/* Vector Compress Instruction */
2835static bool vcompress_vm_check(DisasContext *s, arg_r *a)
2836{
2837    return (vext_check_isa_ill(s) &&
2838            vext_check_reg(s, a->rd, false) &&
2839            vext_check_reg(s, a->rs2, false) &&
2840            vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) &&
2841            (a->rd != a->rs2));
2842}
2843
2844static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
2845{
2846    if (vcompress_vm_check(s, a)) {
2847        uint32_t data = 0;
2848        static gen_helper_gvec_4_ptr * const fns[4] = {
2849            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
2850            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
2851        };
2852        TCGLabel *over = gen_new_label();
2853        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2854
2855        data = FIELD_DP32(data, VDATA, MLEN, s->mlen);
2856        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2857        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2858                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
2859                           cpu_env, s->vlen / 8, s->vlen / 8, data,
2860                           fns[s->sew]);
2861        gen_set_label(over);
2862        return true;
2863    }
2864    return false;
2865}
2866