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