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