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