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