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