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