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