1/*
2 *
3 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2 or later, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "tcg/tcg-op-gvec.h"
18#include "tcg/tcg-gvec-desc.h"
19#include "internals.h"
20
21static inline bool is_overlapped(const int8_t astart, int8_t asize,
22                                 const int8_t bstart, int8_t bsize)
23{
24    const int8_t aend = astart + asize;
25    const int8_t bend = bstart + bsize;
26
27    return MAX(aend, bend) - MIN(astart, bstart) < asize + bsize;
28}
29
30static bool require_rvv(DisasContext *s)
31{
32    return s->mstatus_vs != 0;
33}
34
35static bool require_rvf(DisasContext *s)
36{
37    if (s->mstatus_fs == 0) {
38        return false;
39    }
40
41    switch (s->sew) {
42    case MO_16:
43    case MO_32:
44        return has_ext(s, RVF);
45    case MO_64:
46        return has_ext(s, RVD);
47    default:
48        return false;
49    }
50}
51
52static bool require_scale_rvf(DisasContext *s)
53{
54    if (s->mstatus_fs == 0) {
55        return false;
56    }
57
58    switch (s->sew) {
59    case MO_8:
60    case MO_16:
61        return has_ext(s, RVF);
62    case MO_32:
63        return has_ext(s, RVD);
64    default:
65        return false;
66    }
67}
68
69/* Destination vector register group cannot overlap source mask register. */
70static bool require_vm(int vm, int vd)
71{
72    return (vm != 0 || vd != 0);
73}
74
75static bool require_nf(int vd, int nf, int lmul)
76{
77    int size = nf << MAX(lmul, 0);
78    return size <= 8 && vd + size <= 32;
79}
80
81/*
82 * Vector register should aligned with the passed-in LMUL (EMUL).
83 * If LMUL < 0, i.e. fractional LMUL, any vector register is allowed.
84 */
85static bool require_align(const int8_t val, const int8_t lmul)
86{
87    return lmul <= 0 || extract32(val, 0, lmul) == 0;
88}
89
90/*
91 * A destination vector register group can overlap a source vector
92 * register group only if one of the following holds:
93 *  1. The destination EEW equals the source EEW.
94 *  2. The destination EEW is smaller than the source EEW and the overlap
95 *     is in the lowest-numbered part of the source register group.
96 *  3. The destination EEW is greater than the source EEW, the source EMUL
97 *     is at least 1, and the overlap is in the highest-numbered part of
98 *     the destination register group.
99 * (Section 5.2)
100 *
101 * This function returns true if one of the following holds:
102 *  * Destination vector register group does not overlap a source vector
103 *    register group.
104 *  * Rule 3 met.
105 * For rule 1, overlap is allowed so this function doesn't need to be called.
106 * For rule 2, (vd == vs). Caller has to check whether: (vd != vs) before
107 * calling this function.
108 */
109static bool require_noover(const int8_t dst, const int8_t dst_lmul,
110                           const int8_t src, const int8_t src_lmul)
111{
112    int8_t dst_size = dst_lmul <= 0 ? 1 : 1 << dst_lmul;
113    int8_t src_size = src_lmul <= 0 ? 1 : 1 << src_lmul;
114
115    /* Destination EEW is greater than the source EEW, check rule 3. */
116    if (dst_size > src_size) {
117        if (dst < src &&
118            src_lmul >= 0 &&
119            is_overlapped(dst, dst_size, src, src_size) &&
120            !is_overlapped(dst, dst_size, src + src_size, src_size)) {
121            return true;
122        }
123    }
124
125    return !is_overlapped(dst, dst_size, src, src_size);
126}
127
128static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
129{
130    TCGv s1, dst;
131
132    if (!require_rvv(s) ||
133        !(has_ext(s, RVV) || s->ext_zve64f)) {
134        return false;
135    }
136
137    dst = dest_gpr(s, rd);
138
139    if (rd == 0 && rs1 == 0) {
140        s1 = tcg_temp_new();
141        tcg_gen_mov_tl(s1, cpu_vl);
142    } else if (rs1 == 0) {
143        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
144        s1 = tcg_constant_tl(RV_VLEN_MAX);
145    } else {
146        s1 = get_gpr(s, rs1, EXT_ZERO);
147    }
148
149    gen_helper_vsetvl(dst, cpu_env, s1, s2);
150    gen_set_gpr(s, rd, dst);
151    mark_vs_dirty(s);
152
153    tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn);
154    tcg_gen_lookup_and_goto_ptr();
155    s->base.is_jmp = DISAS_NORETURN;
156
157    if (rd == 0 && rs1 == 0) {
158        tcg_temp_free(s1);
159    }
160
161    return true;
162}
163
164static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2)
165{
166    TCGv dst;
167
168    if (!require_rvv(s) ||
169        !(has_ext(s, RVV) || s->ext_zve64f)) {
170        return false;
171    }
172
173    dst = dest_gpr(s, rd);
174
175    gen_helper_vsetvl(dst, cpu_env, s1, s2);
176    gen_set_gpr(s, rd, dst);
177    mark_vs_dirty(s);
178    tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn);
179    tcg_gen_lookup_and_goto_ptr();
180    s->base.is_jmp = DISAS_NORETURN;
181
182    return true;
183}
184
185static bool trans_vsetvl(DisasContext *s, arg_vsetvl *a)
186{
187    TCGv s2 = get_gpr(s, a->rs2, EXT_ZERO);
188    return do_vsetvl(s, a->rd, a->rs1, s2);
189}
190
191static bool trans_vsetvli(DisasContext *s, arg_vsetvli *a)
192{
193    TCGv s2 = tcg_constant_tl(a->zimm);
194    return do_vsetvl(s, a->rd, a->rs1, s2);
195}
196
197static bool trans_vsetivli(DisasContext *s, arg_vsetivli *a)
198{
199    TCGv s1 = tcg_const_tl(a->rs1);
200    TCGv s2 = tcg_const_tl(a->zimm);
201    return do_vsetivli(s, a->rd, s1, s2);
202}
203
204/* vector register offset from env */
205static uint32_t vreg_ofs(DisasContext *s, int reg)
206{
207    return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
208}
209
210/* check functions */
211
212/*
213 * Vector unit-stride, strided, unit-stride segment, strided segment
214 * store check function.
215 *
216 * Rules to be checked here:
217 *   1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3)
218 *   2. Destination vector register number is multiples of EMUL.
219 *      (Section 3.4.2, 7.3)
220 *   3. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8)
221 *   4. Vector register numbers accessed by the segment load or store
222 *      cannot increment past 31. (Section 7.8)
223 */
224static bool vext_check_store(DisasContext *s, int vd, int nf, uint8_t eew)
225{
226    int8_t emul = eew - s->sew + s->lmul;
227    return (emul >= -3 && emul <= 3) &&
228            require_align(vd, emul) &&
229            require_nf(vd, nf, emul);
230}
231
232/*
233 * Vector unit-stride, strided, unit-stride segment, strided segment
234 * load check function.
235 *
236 * Rules to be checked here:
237 *   1. All rules applies to store instructions are applies
238 *      to load instructions.
239 *   2. Destination vector register group for a masked vector
240 *      instruction cannot overlap the source mask register (v0).
241 *      (Section 5.3)
242 */
243static bool vext_check_load(DisasContext *s, int vd, int nf, int vm,
244                            uint8_t eew)
245{
246    return vext_check_store(s, vd, nf, eew) && require_vm(vm, vd);
247}
248
249/*
250 * Vector indexed, indexed segment store check function.
251 *
252 * Rules to be checked here:
253 *   1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3)
254 *   2. Index vector register number is multiples of EMUL.
255 *      (Section 3.4.2, 7.3)
256 *   3. Destination vector register number is multiples of LMUL.
257 *      (Section 3.4.2, 7.3)
258 *   4. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8)
259 *   5. Vector register numbers accessed by the segment load or store
260 *      cannot increment past 31. (Section 7.8)
261 */
262static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf,
263                                uint8_t eew)
264{
265    int8_t emul = eew - s->sew + s->lmul;
266    return (emul >= -3 && emul <= 3) &&
267            require_align(vs2, emul) &&
268            require_align(vd, s->lmul) &&
269            require_nf(vd, nf, s->lmul);
270}
271
272/*
273 * Vector indexed, indexed segment load check function.
274 *
275 * Rules to be checked here:
276 *   1. All rules applies to store instructions are applies
277 *      to load instructions.
278 *   2. Destination vector register group for a masked vector
279 *      instruction cannot overlap the source mask register (v0).
280 *      (Section 5.3)
281 *   3. Destination vector register cannot overlap a source vector
282 *      register (vs2) group.
283 *      (Section 5.2)
284 *   4. Destination vector register groups cannot overlap
285 *      the source vector register (vs2) group for
286 *      indexed segment load instructions. (Section 7.8.3)
287 */
288static bool vext_check_ld_index(DisasContext *s, int vd, int vs2,
289                                int nf, int vm, uint8_t eew)
290{
291    int8_t seg_vd;
292    int8_t emul = eew - s->sew + s->lmul;
293    bool ret = vext_check_st_index(s, vd, vs2, nf, eew) &&
294        require_vm(vm, vd);
295
296    /* Each segment register group has to follow overlap rules. */
297    for (int i = 0; i < nf; ++i) {
298        seg_vd = vd + (1 << MAX(s->lmul, 0)) * i;
299
300        if (eew > s->sew) {
301            if (seg_vd != vs2) {
302                ret &= require_noover(seg_vd, s->lmul, vs2, emul);
303            }
304        } else if (eew < s->sew) {
305            ret &= require_noover(seg_vd, s->lmul, vs2, emul);
306        }
307
308        /*
309         * Destination vector register groups cannot overlap
310         * the source vector register (vs2) group for
311         * indexed segment load instructions.
312         */
313        if (nf > 1) {
314            ret &= !is_overlapped(seg_vd, 1 << MAX(s->lmul, 0),
315                                  vs2, 1 << MAX(emul, 0));
316        }
317    }
318    return ret;
319}
320
321static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
322{
323    return require_vm(vm, vd) &&
324        require_align(vd, s->lmul) &&
325        require_align(vs, s->lmul);
326}
327
328/*
329 * Check function for vector instruction with format:
330 * single-width result and single-width sources (SEW = SEW op SEW)
331 *
332 * Rules to be checked here:
333 *   1. Destination vector register group for a masked vector
334 *      instruction cannot overlap the source mask register (v0).
335 *      (Section 5.3)
336 *   2. Destination vector register number is multiples of LMUL.
337 *      (Section 3.4.2)
338 *   3. Source (vs2, vs1) vector register number are multiples of LMUL.
339 *      (Section 3.4.2)
340 */
341static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm)
342{
343    return vext_check_ss(s, vd, vs2, vm) &&
344        require_align(vs1, s->lmul);
345}
346
347static bool vext_check_ms(DisasContext *s, int vd, int vs)
348{
349    bool ret = require_align(vs, s->lmul);
350    if (vd != vs) {
351        ret &= require_noover(vd, 0, vs, s->lmul);
352    }
353    return ret;
354}
355
356/*
357 * Check function for maskable vector instruction with format:
358 * single-width result and single-width sources (SEW = SEW op SEW)
359 *
360 * Rules to be checked here:
361 *   1. Source (vs2, vs1) vector register number are multiples of LMUL.
362 *      (Section 3.4.2)
363 *   2. Destination vector register cannot overlap a source vector
364 *      register (vs2, vs1) group.
365 *      (Section 5.2)
366 *   3. The destination vector register group for a masked vector
367 *      instruction cannot overlap the source mask register (v0),
368 *      unless the destination vector register is being written
369 *      with a mask value (e.g., comparisons) or the scalar result
370 *      of a reduction. (Section 5.3)
371 */
372static bool vext_check_mss(DisasContext *s, int vd, int vs1, int vs2)
373{
374    bool ret = vext_check_ms(s, vd, vs2) &&
375        require_align(vs1, s->lmul);
376    if (vd != vs1) {
377        ret &= require_noover(vd, 0, vs1, s->lmul);
378    }
379    return ret;
380}
381
382/*
383 * Common check function for vector widening instructions
384 * of double-width result (2*SEW).
385 *
386 * Rules to be checked here:
387 *   1. The largest vector register group used by an instruction
388 *      can not be greater than 8 vector registers (Section 5.2):
389 *      => LMUL < 8.
390 *      => SEW < 64.
391 *   2. Double-width SEW cannot greater than ELEN.
392 *   3. Destination vector register number is multiples of 2 * LMUL.
393 *      (Section 3.4.2)
394 *   4. Destination vector register group for a masked vector
395 *      instruction cannot overlap the source mask register (v0).
396 *      (Section 5.3)
397 */
398static bool vext_wide_check_common(DisasContext *s, int vd, int vm)
399{
400    return (s->lmul <= 2) &&
401           (s->sew < MO_64) &&
402           ((s->sew + 1) <= (s->elen >> 4)) &&
403           require_align(vd, s->lmul + 1) &&
404           require_vm(vm, vd);
405}
406
407/*
408 * Common check function for vector narrowing instructions
409 * of single-width result (SEW) and double-width source (2*SEW).
410 *
411 * Rules to be checked here:
412 *   1. The largest vector register group used by an instruction
413 *      can not be greater than 8 vector registers (Section 5.2):
414 *      => LMUL < 8.
415 *      => SEW < 64.
416 *   2. Double-width SEW cannot greater than ELEN.
417 *   3. Source vector register number is multiples of 2 * LMUL.
418 *      (Section 3.4.2)
419 *   4. Destination vector register number is multiples of LMUL.
420 *      (Section 3.4.2)
421 *   5. Destination vector register group for a masked vector
422 *      instruction cannot overlap the source mask register (v0).
423 *      (Section 5.3)
424 */
425static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2,
426                                     int vm)
427{
428    return (s->lmul <= 2) &&
429           (s->sew < MO_64) &&
430           ((s->sew + 1) <= (s->elen >> 4)) &&
431           require_align(vs2, s->lmul + 1) &&
432           require_align(vd, s->lmul) &&
433           require_vm(vm, vd);
434}
435
436static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
437{
438    return vext_wide_check_common(s, vd, vm) &&
439        require_align(vs, s->lmul) &&
440        require_noover(vd, s->lmul + 1, vs, s->lmul);
441}
442
443static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
444{
445    return vext_wide_check_common(s, vd, vm) &&
446        require_align(vs, s->lmul + 1);
447}
448
449/*
450 * Check function for vector instruction with format:
451 * double-width result and single-width sources (2*SEW = SEW op SEW)
452 *
453 * Rules to be checked here:
454 *   1. All rules in defined in widen common rules are applied.
455 *   2. Source (vs2, vs1) vector register number are multiples of LMUL.
456 *      (Section 3.4.2)
457 *   3. Destination vector register cannot overlap a source vector
458 *      register (vs2, vs1) group.
459 *      (Section 5.2)
460 */
461static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
462{
463    return vext_check_ds(s, vd, vs2, vm) &&
464        require_align(vs1, s->lmul) &&
465        require_noover(vd, s->lmul + 1, vs1, s->lmul);
466}
467
468/*
469 * Check function for vector instruction with format:
470 * double-width result and double-width source1 and single-width
471 * source2 (2*SEW = 2*SEW op SEW)
472 *
473 * Rules to be checked here:
474 *   1. All rules in defined in widen common rules are applied.
475 *   2. Source 1 (vs2) vector register number is multiples of 2 * LMUL.
476 *      (Section 3.4.2)
477 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
478 *      (Section 3.4.2)
479 *   4. Destination vector register cannot overlap a source vector
480 *      register (vs1) group.
481 *      (Section 5.2)
482 */
483static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm)
484{
485    return vext_check_ds(s, vd, vs1, vm) &&
486        require_align(vs2, s->lmul + 1);
487}
488
489static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
490{
491    bool ret = vext_narrow_check_common(s, vd, vs, vm);
492    if (vd != vs) {
493        ret &= require_noover(vd, s->lmul, vs, s->lmul + 1);
494    }
495    return ret;
496}
497
498/*
499 * Check function for vector instruction with format:
500 * single-width result and double-width source 1 and single-width
501 * source 2 (SEW = 2*SEW op SEW)
502 *
503 * Rules to be checked here:
504 *   1. All rules in defined in narrow common rules are applied.
505 *   2. Destination vector register cannot overlap a source vector
506 *      register (vs2) group.
507 *      (Section 5.2)
508 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
509 *      (Section 3.4.2)
510 */
511static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm)
512{
513    return vext_check_sd(s, vd, vs2, vm) &&
514        require_align(vs1, s->lmul);
515}
516
517/*
518 * Check function for vector reduction instructions.
519 *
520 * Rules to be checked here:
521 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
522 *      (Section 3.4.2)
523 */
524static bool vext_check_reduction(DisasContext *s, int vs2)
525{
526    return require_align(vs2, s->lmul) && (s->vstart == 0);
527}
528
529/*
530 * Check function for vector slide instructions.
531 *
532 * Rules to be checked here:
533 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
534 *      (Section 3.4.2)
535 *   2. Destination vector register number is multiples of LMUL.
536 *      (Section 3.4.2)
537 *   3. Destination vector register group for a masked vector
538 *      instruction cannot overlap the source mask register (v0).
539 *      (Section 5.3)
540 *   4. The destination vector register group for vslideup, vslide1up,
541 *      vfslide1up, cannot overlap the source vector register (vs2) group.
542 *      (Section 5.2, 16.3.1, 16.3.3)
543 */
544static bool vext_check_slide(DisasContext *s, int vd, int vs2,
545                             int vm, bool is_over)
546{
547    bool ret = require_align(vs2, s->lmul) &&
548               require_align(vd, s->lmul) &&
549               require_vm(vm, vd);
550    if (is_over) {
551        ret &= (vd != vs2);
552    }
553    return ret;
554}
555
556/*
557 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
558 * So RVV is also be checked in this function.
559 */
560static bool vext_check_isa_ill(DisasContext *s)
561{
562    return !s->vill;
563}
564
565/* common translation macro */
566#define GEN_VEXT_TRANS(NAME, EEW, ARGTYPE, OP, CHECK)        \
567static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE * a) \
568{                                                            \
569    if (CHECK(s, a, EEW)) {                                  \
570        return OP(s, a, EEW);                                \
571    }                                                        \
572    return false;                                            \
573}
574
575static uint8_t vext_get_emul(DisasContext *s, uint8_t eew)
576{
577    int8_t emul = eew - s->sew + s->lmul;
578    return emul < 0 ? 0 : emul;
579}
580
581/*
582 *** unit stride load and store
583 */
584typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
585                                TCGv_env, TCGv_i32);
586
587static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
588                          gen_helper_ldst_us *fn, DisasContext *s,
589                          bool is_store)
590{
591    TCGv_ptr dest, mask;
592    TCGv base;
593    TCGv_i32 desc;
594
595    TCGLabel *over = gen_new_label();
596    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
597
598    dest = tcg_temp_new_ptr();
599    mask = tcg_temp_new_ptr();
600    base = get_gpr(s, rs1, EXT_NONE);
601
602    /*
603     * As simd_desc supports at most 2048 bytes, and in this implementation,
604     * the max vector group length is 4096 bytes. So split it into two parts.
605     *
606     * The first part is vlen in bytes, encoded in maxsz of simd_desc.
607     * The second part is lmul, encoded in data of simd_desc.
608     */
609    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
610
611    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
612    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
613
614    fn(dest, mask, base, cpu_env, desc);
615
616    tcg_temp_free_ptr(dest);
617    tcg_temp_free_ptr(mask);
618
619    if (!is_store) {
620        mark_vs_dirty(s);
621    }
622
623    gen_set_label(over);
624    return true;
625}
626
627static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
628{
629    uint32_t data = 0;
630    gen_helper_ldst_us *fn;
631    static gen_helper_ldst_us * const fns[2][4] = {
632        /* masked unit stride load */
633        { gen_helper_vle8_v_mask, gen_helper_vle16_v_mask,
634          gen_helper_vle32_v_mask, gen_helper_vle64_v_mask },
635        /* unmasked unit stride load */
636        { gen_helper_vle8_v, gen_helper_vle16_v,
637          gen_helper_vle32_v, gen_helper_vle64_v }
638    };
639
640    fn =  fns[a->vm][eew];
641    if (fn == NULL) {
642        return false;
643    }
644
645    /*
646     * Vector load/store instructions have the EEW encoded
647     * directly in the instructions. The maximum vector size is
648     * calculated with EMUL rather than LMUL.
649     */
650    uint8_t emul = vext_get_emul(s, eew);
651    data = FIELD_DP32(data, VDATA, VM, a->vm);
652    data = FIELD_DP32(data, VDATA, LMUL, emul);
653    data = FIELD_DP32(data, VDATA, NF, a->nf);
654    return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
655}
656
657static bool ld_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew)
658{
659    return require_rvv(s) &&
660           vext_check_isa_ill(s) &&
661           vext_check_load(s, a->rd, a->nf, a->vm, eew);
662}
663
664GEN_VEXT_TRANS(vle8_v,  MO_8,  r2nfvm, ld_us_op, ld_us_check)
665GEN_VEXT_TRANS(vle16_v, MO_16, r2nfvm, ld_us_op, ld_us_check)
666GEN_VEXT_TRANS(vle32_v, MO_32, r2nfvm, ld_us_op, ld_us_check)
667GEN_VEXT_TRANS(vle64_v, MO_64, r2nfvm, ld_us_op, ld_us_check)
668
669static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
670{
671    uint32_t data = 0;
672    gen_helper_ldst_us *fn;
673    static gen_helper_ldst_us * const fns[2][4] = {
674        /* masked unit stride store */
675        { gen_helper_vse8_v_mask, gen_helper_vse16_v_mask,
676          gen_helper_vse32_v_mask, gen_helper_vse64_v_mask },
677        /* unmasked unit stride store */
678        { gen_helper_vse8_v, gen_helper_vse16_v,
679          gen_helper_vse32_v, gen_helper_vse64_v }
680    };
681
682    fn =  fns[a->vm][eew];
683    if (fn == NULL) {
684        return false;
685    }
686
687    uint8_t emul = vext_get_emul(s, eew);
688    data = FIELD_DP32(data, VDATA, VM, a->vm);
689    data = FIELD_DP32(data, VDATA, LMUL, emul);
690    data = FIELD_DP32(data, VDATA, NF, a->nf);
691    return ldst_us_trans(a->rd, a->rs1, data, fn, s, true);
692}
693
694static bool st_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew)
695{
696    return require_rvv(s) &&
697           vext_check_isa_ill(s) &&
698           vext_check_store(s, a->rd, a->nf, eew);
699}
700
701GEN_VEXT_TRANS(vse8_v,  MO_8,  r2nfvm, st_us_op, st_us_check)
702GEN_VEXT_TRANS(vse16_v, MO_16, r2nfvm, st_us_op, st_us_check)
703GEN_VEXT_TRANS(vse32_v, MO_32, r2nfvm, st_us_op, st_us_check)
704GEN_VEXT_TRANS(vse64_v, MO_64, r2nfvm, st_us_op, st_us_check)
705
706/*
707 *** unit stride mask load and store
708 */
709static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew)
710{
711    uint32_t data = 0;
712    gen_helper_ldst_us *fn = gen_helper_vlm_v;
713
714    /* EMUL = 1, NFIELDS = 1 */
715    data = FIELD_DP32(data, VDATA, LMUL, 0);
716    data = FIELD_DP32(data, VDATA, NF, 1);
717    return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
718}
719
720static bool ld_us_mask_check(DisasContext *s, arg_vlm_v *a, uint8_t eew)
721{
722    /* EMUL = 1, NFIELDS = 1 */
723    return require_rvv(s) && vext_check_isa_ill(s);
724}
725
726static bool st_us_mask_op(DisasContext *s, arg_vsm_v *a, uint8_t eew)
727{
728    uint32_t data = 0;
729    gen_helper_ldst_us *fn = gen_helper_vsm_v;
730
731    /* EMUL = 1, NFIELDS = 1 */
732    data = FIELD_DP32(data, VDATA, LMUL, 0);
733    data = FIELD_DP32(data, VDATA, NF, 1);
734    return ldst_us_trans(a->rd, a->rs1, data, fn, s, true);
735}
736
737static bool st_us_mask_check(DisasContext *s, arg_vsm_v *a, uint8_t eew)
738{
739    /* EMUL = 1, NFIELDS = 1 */
740    return require_rvv(s) && vext_check_isa_ill(s);
741}
742
743GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld_us_mask_check)
744GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check)
745
746/*
747 *** stride load and store
748 */
749typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
750                                    TCGv, TCGv_env, TCGv_i32);
751
752static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
753                              uint32_t data, gen_helper_ldst_stride *fn,
754                              DisasContext *s, bool is_store)
755{
756    TCGv_ptr dest, mask;
757    TCGv base, stride;
758    TCGv_i32 desc;
759
760    TCGLabel *over = gen_new_label();
761    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
762
763    dest = tcg_temp_new_ptr();
764    mask = tcg_temp_new_ptr();
765    base = get_gpr(s, rs1, EXT_NONE);
766    stride = get_gpr(s, rs2, EXT_NONE);
767    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
768
769    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
770    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
771
772    fn(dest, mask, base, stride, cpu_env, desc);
773
774    tcg_temp_free_ptr(dest);
775    tcg_temp_free_ptr(mask);
776
777    if (!is_store) {
778        mark_vs_dirty(s);
779    }
780
781    gen_set_label(over);
782    return true;
783}
784
785static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
786{
787    uint32_t data = 0;
788    gen_helper_ldst_stride *fn;
789    static gen_helper_ldst_stride * const fns[4] = {
790        gen_helper_vlse8_v, gen_helper_vlse16_v,
791        gen_helper_vlse32_v, gen_helper_vlse64_v
792    };
793
794    fn = fns[eew];
795    if (fn == NULL) {
796        return false;
797    }
798
799    uint8_t emul = vext_get_emul(s, eew);
800    data = FIELD_DP32(data, VDATA, VM, a->vm);
801    data = FIELD_DP32(data, VDATA, LMUL, emul);
802    data = FIELD_DP32(data, VDATA, NF, a->nf);
803    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
804}
805
806static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
807{
808    return require_rvv(s) &&
809           vext_check_isa_ill(s) &&
810           vext_check_load(s, a->rd, a->nf, a->vm, eew);
811}
812
813GEN_VEXT_TRANS(vlse8_v,  MO_8,  rnfvm, ld_stride_op, ld_stride_check)
814GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check)
815GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check)
816GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check)
817
818static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
819{
820    uint32_t data = 0;
821    gen_helper_ldst_stride *fn;
822    static gen_helper_ldst_stride * const fns[4] = {
823        /* masked stride store */
824        gen_helper_vsse8_v,  gen_helper_vsse16_v,
825        gen_helper_vsse32_v,  gen_helper_vsse64_v
826    };
827
828    uint8_t emul = vext_get_emul(s, eew);
829    data = FIELD_DP32(data, VDATA, VM, a->vm);
830    data = FIELD_DP32(data, VDATA, LMUL, emul);
831    data = FIELD_DP32(data, VDATA, NF, a->nf);
832    fn = fns[eew];
833    if (fn == NULL) {
834        return false;
835    }
836
837    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
838}
839
840static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
841{
842    return require_rvv(s) &&
843           vext_check_isa_ill(s) &&
844           vext_check_store(s, a->rd, a->nf, eew);
845}
846
847GEN_VEXT_TRANS(vsse8_v,  MO_8,  rnfvm, st_stride_op, st_stride_check)
848GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check)
849GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check)
850GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check)
851
852/*
853 *** index load and store
854 */
855typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
856                                   TCGv_ptr, TCGv_env, TCGv_i32);
857
858static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
859                             uint32_t data, gen_helper_ldst_index *fn,
860                             DisasContext *s, bool is_store)
861{
862    TCGv_ptr dest, mask, index;
863    TCGv base;
864    TCGv_i32 desc;
865
866    TCGLabel *over = gen_new_label();
867    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
868
869    dest = tcg_temp_new_ptr();
870    mask = tcg_temp_new_ptr();
871    index = tcg_temp_new_ptr();
872    base = get_gpr(s, rs1, EXT_NONE);
873    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
874
875    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
876    tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
877    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
878
879    fn(dest, mask, base, index, cpu_env, desc);
880
881    tcg_temp_free_ptr(dest);
882    tcg_temp_free_ptr(mask);
883    tcg_temp_free_ptr(index);
884
885    if (!is_store) {
886        mark_vs_dirty(s);
887    }
888
889    gen_set_label(over);
890    return true;
891}
892
893static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
894{
895    uint32_t data = 0;
896    gen_helper_ldst_index *fn;
897    static gen_helper_ldst_index * const fns[4][4] = {
898        /*
899         * offset vector register group EEW = 8,
900         * data vector register group EEW = SEW
901         */
902        { gen_helper_vlxei8_8_v,  gen_helper_vlxei8_16_v,
903          gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v },
904        /*
905         * offset vector register group EEW = 16,
906         * data vector register group EEW = SEW
907         */
908        { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v,
909          gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v },
910        /*
911         * offset vector register group EEW = 32,
912         * data vector register group EEW = SEW
913         */
914        { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v,
915          gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v },
916        /*
917         * offset vector register group EEW = 64,
918         * data vector register group EEW = SEW
919         */
920        { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v,
921          gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v }
922    };
923
924    fn = fns[eew][s->sew];
925
926    uint8_t emul = vext_get_emul(s, s->sew);
927    data = FIELD_DP32(data, VDATA, VM, a->vm);
928    data = FIELD_DP32(data, VDATA, LMUL, emul);
929    data = FIELD_DP32(data, VDATA, NF, a->nf);
930    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
931}
932
933static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
934{
935    return require_rvv(s) &&
936           vext_check_isa_ill(s) &&
937           vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew);
938}
939
940GEN_VEXT_TRANS(vlxei8_v,  MO_8,  rnfvm, ld_index_op, ld_index_check)
941GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check)
942GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check)
943GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check)
944
945static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
946{
947    uint32_t data = 0;
948    gen_helper_ldst_index *fn;
949    static gen_helper_ldst_index * const fns[4][4] = {
950        /*
951         * offset vector register group EEW = 8,
952         * data vector register group EEW = SEW
953         */
954        { gen_helper_vsxei8_8_v,  gen_helper_vsxei8_16_v,
955          gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v },
956        /*
957         * offset vector register group EEW = 16,
958         * data vector register group EEW = SEW
959         */
960        { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v,
961          gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v },
962        /*
963         * offset vector register group EEW = 32,
964         * data vector register group EEW = SEW
965         */
966        { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v,
967          gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v },
968        /*
969         * offset vector register group EEW = 64,
970         * data vector register group EEW = SEW
971         */
972        { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v,
973          gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v }
974    };
975
976    fn = fns[eew][s->sew];
977
978    uint8_t emul = vext_get_emul(s, s->sew);
979    data = FIELD_DP32(data, VDATA, VM, a->vm);
980    data = FIELD_DP32(data, VDATA, LMUL, emul);
981    data = FIELD_DP32(data, VDATA, NF, a->nf);
982    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
983}
984
985static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
986{
987    return require_rvv(s) &&
988           vext_check_isa_ill(s) &&
989           vext_check_st_index(s, a->rd, a->rs2, a->nf, eew);
990}
991
992GEN_VEXT_TRANS(vsxei8_v,  MO_8,  rnfvm, st_index_op, st_index_check)
993GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check)
994GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check)
995GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check)
996
997/*
998 *** unit stride fault-only-first load
999 */
1000static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
1001                       gen_helper_ldst_us *fn, DisasContext *s)
1002{
1003    TCGv_ptr dest, mask;
1004    TCGv base;
1005    TCGv_i32 desc;
1006
1007    TCGLabel *over = gen_new_label();
1008    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1009
1010    dest = tcg_temp_new_ptr();
1011    mask = tcg_temp_new_ptr();
1012    base = get_gpr(s, rs1, EXT_NONE);
1013    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1014
1015    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1016    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1017
1018    fn(dest, mask, base, cpu_env, desc);
1019
1020    tcg_temp_free_ptr(dest);
1021    tcg_temp_free_ptr(mask);
1022    mark_vs_dirty(s);
1023    gen_set_label(over);
1024    return true;
1025}
1026
1027static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
1028{
1029    uint32_t data = 0;
1030    gen_helper_ldst_us *fn;
1031    static gen_helper_ldst_us * const fns[4] = {
1032        gen_helper_vle8ff_v, gen_helper_vle16ff_v,
1033        gen_helper_vle32ff_v, gen_helper_vle64ff_v
1034    };
1035
1036    fn = fns[eew];
1037    if (fn == NULL) {
1038        return false;
1039    }
1040
1041    uint8_t emul = vext_get_emul(s, eew);
1042    data = FIELD_DP32(data, VDATA, VM, a->vm);
1043    data = FIELD_DP32(data, VDATA, LMUL, emul);
1044    data = FIELD_DP32(data, VDATA, NF, a->nf);
1045    return ldff_trans(a->rd, a->rs1, data, fn, s);
1046}
1047
1048GEN_VEXT_TRANS(vle8ff_v,  MO_8,  r2nfvm, ldff_op, ld_us_check)
1049GEN_VEXT_TRANS(vle16ff_v, MO_16, r2nfvm, ldff_op, ld_us_check)
1050GEN_VEXT_TRANS(vle32ff_v, MO_32, r2nfvm, ldff_op, ld_us_check)
1051GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check)
1052
1053/*
1054 * load and store whole register instructions
1055 */
1056typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32);
1057
1058static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf,
1059                             gen_helper_ldst_whole *fn, DisasContext *s,
1060                             bool is_store)
1061{
1062    TCGv_ptr dest;
1063    TCGv base;
1064    TCGv_i32 desc;
1065
1066    uint32_t data = FIELD_DP32(0, VDATA, NF, nf);
1067    dest = tcg_temp_new_ptr();
1068    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1069
1070    base = get_gpr(s, rs1, EXT_NONE);
1071    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1072
1073    fn(dest, base, cpu_env, desc);
1074
1075    tcg_temp_free_ptr(dest);
1076
1077    if (!is_store) {
1078        mark_vs_dirty(s);
1079    }
1080
1081    return true;
1082}
1083
1084/*
1085 * load and store whole register instructions ignore vtype and vl setting.
1086 * Thus, we don't need to check vill bit. (Section 7.9)
1087 */
1088#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, IS_STORE)                      \
1089static bool trans_##NAME(DisasContext *s, arg_##NAME * a)                 \
1090{                                                                         \
1091    if (require_rvv(s) &&                                                 \
1092        QEMU_IS_ALIGNED(a->rd, ARG_NF)) {                                 \
1093        return ldst_whole_trans(a->rd, a->rs1, ARG_NF, gen_helper_##NAME, \
1094                                s, IS_STORE);                             \
1095    }                                                                     \
1096    return false;                                                         \
1097}
1098
1099GEN_LDST_WHOLE_TRANS(vl1re8_v,  1, false)
1100GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, false)
1101GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, false)
1102GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, false)
1103GEN_LDST_WHOLE_TRANS(vl2re8_v,  2, false)
1104GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, false)
1105GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, false)
1106GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, false)
1107GEN_LDST_WHOLE_TRANS(vl4re8_v,  4, false)
1108GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, false)
1109GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, false)
1110GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, false)
1111GEN_LDST_WHOLE_TRANS(vl8re8_v,  8, false)
1112GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, false)
1113GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, false)
1114GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, false)
1115
1116GEN_LDST_WHOLE_TRANS(vs1r_v, 1, true)
1117GEN_LDST_WHOLE_TRANS(vs2r_v, 2, true)
1118GEN_LDST_WHOLE_TRANS(vs4r_v, 4, true)
1119GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true)
1120
1121/*
1122 *** Vector Integer Arithmetic Instructions
1123 */
1124
1125/*
1126 * MAXSZ returns the maximum vector size can be operated in bytes,
1127 * which is used in GVEC IR when vl_eq_vlmax flag is set to true
1128 * to accerlate vector operation.
1129 */
1130static inline uint32_t MAXSZ(DisasContext *s)
1131{
1132    int scale = s->lmul - 3;
1133    return scale < 0 ? s->vlen >> -scale : s->vlen << scale;
1134}
1135
1136static bool opivv_check(DisasContext *s, arg_rmrr *a)
1137{
1138    return require_rvv(s) &&
1139           vext_check_isa_ill(s) &&
1140           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1141}
1142
1143typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
1144                        uint32_t, uint32_t, uint32_t);
1145
1146static inline bool
1147do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
1148              gen_helper_gvec_4_ptr *fn)
1149{
1150    TCGLabel *over = gen_new_label();
1151    if (!opivv_check(s, a)) {
1152        return false;
1153    }
1154
1155    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1156
1157    if (a->vm && s->vl_eq_vlmax) {
1158        gvec_fn(s->sew, vreg_ofs(s, a->rd),
1159                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
1160                MAXSZ(s), MAXSZ(s));
1161    } else {
1162        uint32_t data = 0;
1163
1164        data = FIELD_DP32(data, VDATA, VM, a->vm);
1165        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1166        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1167                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
1168                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1169    }
1170    mark_vs_dirty(s);
1171    gen_set_label(over);
1172    return true;
1173}
1174
1175/* OPIVV with GVEC IR */
1176#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
1177static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1178{                                                                  \
1179    static gen_helper_gvec_4_ptr * const fns[4] = {                \
1180        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1181        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1182    };                                                             \
1183    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1184}
1185
1186GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
1187GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
1188
1189typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
1190                              TCGv_env, TCGv_i32);
1191
1192static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
1193                        gen_helper_opivx *fn, DisasContext *s)
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 = get_gpr(s, rs1, EXT_NONE);
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
1226static bool opivx_check(DisasContext *s, arg_rmrr *a)
1227{
1228    return require_rvv(s) &&
1229           vext_check_isa_ill(s) &&
1230           vext_check_ss(s, a->rd, a->rs2, a->vm);
1231}
1232
1233typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
1234                         uint32_t, uint32_t);
1235
1236static inline bool
1237do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
1238              gen_helper_opivx *fn)
1239{
1240    if (!opivx_check(s, a)) {
1241        return false;
1242    }
1243
1244    if (a->vm && s->vl_eq_vlmax) {
1245        TCGv_i64 src1 = tcg_temp_new_i64();
1246
1247        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
1248        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1249                src1, MAXSZ(s), MAXSZ(s));
1250
1251        tcg_temp_free_i64(src1);
1252        mark_vs_dirty(s);
1253        return true;
1254    }
1255    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1256}
1257
1258/* OPIVX with GVEC IR */
1259#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
1260static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1261{                                                                  \
1262    static gen_helper_opivx * const fns[4] = {                     \
1263        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1264        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1265    };                                                             \
1266    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1267}
1268
1269GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
1270GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
1271
1272static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1273{
1274    tcg_gen_vec_sub8_i64(d, b, a);
1275}
1276
1277static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1278{
1279    tcg_gen_vec_sub16_i64(d, b, a);
1280}
1281
1282static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1283{
1284    tcg_gen_sub_i32(ret, arg2, arg1);
1285}
1286
1287static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1288{
1289    tcg_gen_sub_i64(ret, arg2, arg1);
1290}
1291
1292static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
1293{
1294    tcg_gen_sub_vec(vece, r, b, a);
1295}
1296
1297static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
1298                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
1299{
1300    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
1301    static const GVecGen2s rsub_op[4] = {
1302        { .fni8 = gen_vec_rsub8_i64,
1303          .fniv = gen_rsub_vec,
1304          .fno = gen_helper_vec_rsubs8,
1305          .opt_opc = vecop_list,
1306          .vece = MO_8 },
1307        { .fni8 = gen_vec_rsub16_i64,
1308          .fniv = gen_rsub_vec,
1309          .fno = gen_helper_vec_rsubs16,
1310          .opt_opc = vecop_list,
1311          .vece = MO_16 },
1312        { .fni4 = gen_rsub_i32,
1313          .fniv = gen_rsub_vec,
1314          .fno = gen_helper_vec_rsubs32,
1315          .opt_opc = vecop_list,
1316          .vece = MO_32 },
1317        { .fni8 = gen_rsub_i64,
1318          .fniv = gen_rsub_vec,
1319          .fno = gen_helper_vec_rsubs64,
1320          .opt_opc = vecop_list,
1321          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
1322          .vece = MO_64 },
1323    };
1324
1325    tcg_debug_assert(vece <= MO_64);
1326    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
1327}
1328
1329GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1330
1331typedef enum {
1332    IMM_ZX,         /* Zero-extended */
1333    IMM_SX,         /* Sign-extended */
1334    IMM_TRUNC_SEW,  /* Truncate to log(SEW) bits */
1335    IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */
1336} imm_mode_t;
1337
1338static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode)
1339{
1340    switch (imm_mode) {
1341    case IMM_ZX:
1342        return extract64(imm, 0, 5);
1343    case IMM_SX:
1344        return sextract64(imm, 0, 5);
1345    case IMM_TRUNC_SEW:
1346        return extract64(imm, 0, s->sew + 3);
1347    case IMM_TRUNC_2SEW:
1348        return extract64(imm, 0, s->sew + 4);
1349    default:
1350        g_assert_not_reached();
1351    }
1352}
1353
1354static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1355                        gen_helper_opivx *fn, DisasContext *s,
1356                        imm_mode_t imm_mode)
1357{
1358    TCGv_ptr dest, src2, mask;
1359    TCGv src1;
1360    TCGv_i32 desc;
1361    uint32_t data = 0;
1362
1363    TCGLabel *over = gen_new_label();
1364    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1365
1366    dest = tcg_temp_new_ptr();
1367    mask = tcg_temp_new_ptr();
1368    src2 = tcg_temp_new_ptr();
1369    src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode));
1370
1371    data = FIELD_DP32(data, VDATA, VM, vm);
1372    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1373    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1374
1375    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1376    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1377    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1378
1379    fn(dest, mask, src1, src2, cpu_env, desc);
1380
1381    tcg_temp_free_ptr(dest);
1382    tcg_temp_free_ptr(mask);
1383    tcg_temp_free_ptr(src2);
1384    mark_vs_dirty(s);
1385    gen_set_label(over);
1386    return true;
1387}
1388
1389typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1390                         uint32_t, uint32_t);
1391
1392static inline bool
1393do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1394              gen_helper_opivx *fn, imm_mode_t imm_mode)
1395{
1396    if (!opivx_check(s, a)) {
1397        return false;
1398    }
1399
1400    if (a->vm && s->vl_eq_vlmax) {
1401        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1402                extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
1403        mark_vs_dirty(s);
1404        return true;
1405    }
1406    return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode);
1407}
1408
1409/* OPIVI with GVEC IR */
1410#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \
1411static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1412{                                                                  \
1413    static gen_helper_opivx * const fns[4] = {                     \
1414        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1415        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1416    };                                                             \
1417    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1418                         fns[s->sew], IMM_MODE);                   \
1419}
1420
1421GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi)
1422
1423static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1424                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1425{
1426    TCGv_i64 tmp = tcg_constant_i64(c);
1427    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1428}
1429
1430GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi)
1431
1432/* Vector Widening Integer Add/Subtract */
1433
1434/* OPIVV with WIDEN */
1435static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1436{
1437    return require_rvv(s) &&
1438           vext_check_isa_ill(s) &&
1439           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
1440}
1441
1442static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1443                           gen_helper_gvec_4_ptr *fn,
1444                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1445{
1446    if (checkfn(s, a)) {
1447        uint32_t data = 0;
1448        TCGLabel *over = gen_new_label();
1449        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1450
1451        data = FIELD_DP32(data, VDATA, VM, a->vm);
1452        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1453        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1454                           vreg_ofs(s, a->rs1),
1455                           vreg_ofs(s, a->rs2),
1456                           cpu_env, s->vlen / 8, s->vlen / 8,
1457                           data, fn);
1458        mark_vs_dirty(s);
1459        gen_set_label(over);
1460        return true;
1461    }
1462    return false;
1463}
1464
1465#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1466static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1467{                                                            \
1468    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1469        gen_helper_##NAME##_b,                               \
1470        gen_helper_##NAME##_h,                               \
1471        gen_helper_##NAME##_w                                \
1472    };                                                       \
1473    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1474}
1475
1476GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1477GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1478GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1479GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1480
1481/* OPIVX with WIDEN */
1482static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1483{
1484    return require_rvv(s) &&
1485           vext_check_isa_ill(s) &&
1486           vext_check_ds(s, a->rd, a->rs2, a->vm);
1487}
1488
1489static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1490                           gen_helper_opivx *fn)
1491{
1492    if (opivx_widen_check(s, a)) {
1493        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1494    }
1495    return false;
1496}
1497
1498#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1499static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1500{                                                            \
1501    static gen_helper_opivx * const fns[3] = {               \
1502        gen_helper_##NAME##_b,                               \
1503        gen_helper_##NAME##_h,                               \
1504        gen_helper_##NAME##_w                                \
1505    };                                                       \
1506    return do_opivx_widen(s, a, fns[s->sew]);                \
1507}
1508
1509GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1510GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1511GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1512GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1513
1514/* WIDEN OPIVV with WIDEN */
1515static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1516{
1517    return require_rvv(s) &&
1518           vext_check_isa_ill(s) &&
1519           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
1520}
1521
1522static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1523                           gen_helper_gvec_4_ptr *fn)
1524{
1525    if (opiwv_widen_check(s, a)) {
1526        uint32_t data = 0;
1527        TCGLabel *over = gen_new_label();
1528        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1529
1530        data = FIELD_DP32(data, VDATA, VM, a->vm);
1531        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1532        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1533                           vreg_ofs(s, a->rs1),
1534                           vreg_ofs(s, a->rs2),
1535                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1536        mark_vs_dirty(s);
1537        gen_set_label(over);
1538        return true;
1539    }
1540    return false;
1541}
1542
1543#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1544static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1545{                                                            \
1546    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1547        gen_helper_##NAME##_b,                               \
1548        gen_helper_##NAME##_h,                               \
1549        gen_helper_##NAME##_w                                \
1550    };                                                       \
1551    return do_opiwv_widen(s, a, fns[s->sew]);                \
1552}
1553
1554GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1555GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1556GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1557GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1558
1559/* WIDEN OPIVX with WIDEN */
1560static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1561{
1562    return require_rvv(s) &&
1563           vext_check_isa_ill(s) &&
1564           vext_check_dd(s, a->rd, a->rs2, a->vm);
1565}
1566
1567static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1568                           gen_helper_opivx *fn)
1569{
1570    if (opiwx_widen_check(s, a)) {
1571        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1572    }
1573    return false;
1574}
1575
1576#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1577static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1578{                                                            \
1579    static gen_helper_opivx * const fns[3] = {               \
1580        gen_helper_##NAME##_b,                               \
1581        gen_helper_##NAME##_h,                               \
1582        gen_helper_##NAME##_w                                \
1583    };                                                       \
1584    return do_opiwx_widen(s, a, fns[s->sew]);                \
1585}
1586
1587GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1588GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1589GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1590GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1591
1592/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1593/* OPIVV without GVEC IR */
1594#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1595static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1596{                                                                  \
1597    if (CHECK(s, a)) {                                             \
1598        uint32_t data = 0;                                         \
1599        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1600            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1601            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1602        };                                                         \
1603        TCGLabel *over = gen_new_label();                          \
1604        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1605                                                                   \
1606        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1607        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1608        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1609                           vreg_ofs(s, a->rs1),                    \
1610                           vreg_ofs(s, a->rs2), cpu_env,           \
1611                           s->vlen / 8, s->vlen / 8, data,         \
1612                           fns[s->sew]);                           \
1613        mark_vs_dirty(s);                                          \
1614        gen_set_label(over);                                       \
1615        return true;                                               \
1616    }                                                              \
1617    return false;                                                  \
1618}
1619
1620/*
1621 * For vadc and vsbc, an illegal instruction exception is raised if the
1622 * destination vector register is v0 and LMUL > 1. (Section 11.4)
1623 */
1624static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1625{
1626    return require_rvv(s) &&
1627           vext_check_isa_ill(s) &&
1628           (a->rd != 0) &&
1629           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1630}
1631
1632GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1633GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1634
1635/*
1636 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1637 * destination vector register overlaps a source vector register group.
1638 */
1639static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1640{
1641    return require_rvv(s) &&
1642           vext_check_isa_ill(s) &&
1643           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1644}
1645
1646GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1647GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1648
1649static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1650{
1651    return require_rvv(s) &&
1652           vext_check_isa_ill(s) &&
1653           (a->rd != 0) &&
1654           vext_check_ss(s, a->rd, a->rs2, a->vm);
1655}
1656
1657/* OPIVX without GVEC IR */
1658#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1659static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1660{                                                                        \
1661    if (CHECK(s, a)) {                                                   \
1662        static gen_helper_opivx * const fns[4] = {                       \
1663            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1664            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1665        };                                                               \
1666                                                                         \
1667        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1668    }                                                                    \
1669    return false;                                                        \
1670}
1671
1672GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1673GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1674
1675static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1676{
1677    return require_rvv(s) &&
1678           vext_check_isa_ill(s) &&
1679           vext_check_ms(s, a->rd, a->rs2);
1680}
1681
1682GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1683GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1684
1685/* OPIVI without GVEC IR */
1686#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK)                    \
1687static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1688{                                                                        \
1689    if (CHECK(s, a)) {                                                   \
1690        static gen_helper_opivx * const fns[4] = {                       \
1691            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1692            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1693        };                                                               \
1694        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1695                           fns[s->sew], s, IMM_MODE);                    \
1696    }                                                                    \
1697    return false;                                                        \
1698}
1699
1700GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check)
1701GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check)
1702
1703/* Vector Bitwise Logical Instructions */
1704GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1705GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1706GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1707GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1708GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1709GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1710GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi)
1711GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx,  ori)
1712GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori)
1713
1714/* Vector Single-Width Bit Shift Instructions */
1715GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1716GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1717GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1718
1719typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1720                           uint32_t, uint32_t);
1721
1722static inline bool
1723do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1724                    gen_helper_opivx *fn)
1725{
1726    if (!opivx_check(s, a)) {
1727        return false;
1728    }
1729
1730    if (a->vm && s->vl_eq_vlmax) {
1731        TCGv_i32 src1 = tcg_temp_new_i32();
1732
1733        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1734        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1735        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1736                src1, MAXSZ(s), MAXSZ(s));
1737
1738        tcg_temp_free_i32(src1);
1739        mark_vs_dirty(s);
1740        return true;
1741    }
1742    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1743}
1744
1745#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1746static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1747{                                                                         \
1748    static gen_helper_opivx * const fns[4] = {                            \
1749        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1750        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1751    };                                                                    \
1752                                                                          \
1753    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1754}
1755
1756GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1757GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1758GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1759
1760GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_TRUNC_SEW, vsll_vx, shli)
1761GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_TRUNC_SEW, vsrl_vx, shri)
1762GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_TRUNC_SEW, vsra_vx, sari)
1763
1764/* Vector Narrowing Integer Right Shift Instructions */
1765static bool opiwv_narrow_check(DisasContext *s, arg_rmrr *a)
1766{
1767    return require_rvv(s) &&
1768           vext_check_isa_ill(s) &&
1769           vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm);
1770}
1771
1772/* OPIVV with NARROW */
1773#define GEN_OPIWV_NARROW_TRANS(NAME)                               \
1774static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1775{                                                                  \
1776    if (opiwv_narrow_check(s, a)) {                                \
1777        uint32_t data = 0;                                         \
1778        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1779            gen_helper_##NAME##_b,                                 \
1780            gen_helper_##NAME##_h,                                 \
1781            gen_helper_##NAME##_w,                                 \
1782        };                                                         \
1783        TCGLabel *over = gen_new_label();                          \
1784        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1785                                                                   \
1786        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1787        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1788        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1789                           vreg_ofs(s, a->rs1),                    \
1790                           vreg_ofs(s, a->rs2), cpu_env,           \
1791                           s->vlen / 8, s->vlen / 8, data,         \
1792                           fns[s->sew]);                           \
1793        mark_vs_dirty(s);                                          \
1794        gen_set_label(over);                                       \
1795        return true;                                               \
1796    }                                                              \
1797    return false;                                                  \
1798}
1799GEN_OPIWV_NARROW_TRANS(vnsra_wv)
1800GEN_OPIWV_NARROW_TRANS(vnsrl_wv)
1801
1802static bool opiwx_narrow_check(DisasContext *s, arg_rmrr *a)
1803{
1804    return require_rvv(s) &&
1805           vext_check_isa_ill(s) &&
1806           vext_check_sd(s, a->rd, a->rs2, a->vm);
1807}
1808
1809/* OPIVX with NARROW */
1810#define GEN_OPIWX_NARROW_TRANS(NAME)                                     \
1811static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1812{                                                                        \
1813    if (opiwx_narrow_check(s, a)) {                                      \
1814        static gen_helper_opivx * const fns[3] = {                       \
1815            gen_helper_##NAME##_b,                                       \
1816            gen_helper_##NAME##_h,                                       \
1817            gen_helper_##NAME##_w,                                       \
1818        };                                                               \
1819        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1820    }                                                                    \
1821    return false;                                                        \
1822}
1823
1824GEN_OPIWX_NARROW_TRANS(vnsra_wx)
1825GEN_OPIWX_NARROW_TRANS(vnsrl_wx)
1826
1827/* OPIWI with NARROW */
1828#define GEN_OPIWI_NARROW_TRANS(NAME, IMM_MODE, OPIVX)                    \
1829static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1830{                                                                        \
1831    if (opiwx_narrow_check(s, a)) {                                      \
1832        static gen_helper_opivx * const fns[3] = {                       \
1833            gen_helper_##OPIVX##_b,                                      \
1834            gen_helper_##OPIVX##_h,                                      \
1835            gen_helper_##OPIVX##_w,                                      \
1836        };                                                               \
1837        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1838                           fns[s->sew], s, IMM_MODE);                    \
1839    }                                                                    \
1840    return false;                                                        \
1841}
1842
1843GEN_OPIWI_NARROW_TRANS(vnsra_wi, IMM_ZX, vnsra_wx)
1844GEN_OPIWI_NARROW_TRANS(vnsrl_wi, IMM_ZX, vnsrl_wx)
1845
1846/* Vector Integer Comparison Instructions */
1847/*
1848 * For all comparison instructions, an illegal instruction exception is raised
1849 * if the destination vector register overlaps a source vector register group
1850 * and LMUL > 1.
1851 */
1852static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1853{
1854    return require_rvv(s) &&
1855           vext_check_isa_ill(s) &&
1856           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1857}
1858
1859GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1860GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1861GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1862GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1863GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1864GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1865
1866static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1867{
1868    return require_rvv(s) &&
1869           vext_check_isa_ill(s) &&
1870           vext_check_ms(s, a->rd, a->rs2);
1871}
1872
1873GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1874GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1875GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1876GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1877GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1878GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1879GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1880GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1881
1882GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check)
1883GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check)
1884GEN_OPIVI_TRANS(vmsleu_vi, IMM_SX, vmsleu_vx, opivx_cmp_check)
1885GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check)
1886GEN_OPIVI_TRANS(vmsgtu_vi, IMM_SX, vmsgtu_vx, opivx_cmp_check)
1887GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check)
1888
1889/* Vector Integer Min/Max Instructions */
1890GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1891GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1892GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1893GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1894GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1895GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1896GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1897GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1898
1899/* Vector Single-Width Integer Multiply Instructions */
1900GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1901GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1902GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1903GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1904GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1905GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1906GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1907GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1908
1909/* Vector Integer Divide Instructions */
1910GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1911GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1912GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1913GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1914GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1915GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1916GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1917GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1918
1919/* Vector Widening Integer Multiply Instructions */
1920GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1921GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1922GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1923GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1924GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1925GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1926
1927/* Vector Single-Width Integer Multiply-Add Instructions */
1928GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1929GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1930GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1931GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1932GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1933GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1934GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1935GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1936
1937/* Vector Widening Integer Multiply-Add Instructions */
1938GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1939GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1940GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1941GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1942GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1943GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1944GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1945
1946/* Vector Integer Merge and Move Instructions */
1947static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1948{
1949    if (require_rvv(s) &&
1950        vext_check_isa_ill(s) &&
1951        /* vmv.v.v has rs2 = 0 and vm = 1 */
1952        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
1953        if (s->vl_eq_vlmax) {
1954            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1955                             vreg_ofs(s, a->rs1),
1956                             MAXSZ(s), MAXSZ(s));
1957        } else {
1958            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1959            static gen_helper_gvec_2_ptr * const fns[4] = {
1960                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1961                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1962            };
1963            TCGLabel *over = gen_new_label();
1964            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1965
1966            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1967                               cpu_env, s->vlen / 8, s->vlen / 8, data,
1968                               fns[s->sew]);
1969            gen_set_label(over);
1970        }
1971        mark_vs_dirty(s);
1972        return true;
1973    }
1974    return false;
1975}
1976
1977typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1978static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1979{
1980    if (require_rvv(s) &&
1981        vext_check_isa_ill(s) &&
1982        /* vmv.v.x has rs2 = 0 and vm = 1 */
1983        vext_check_ss(s, a->rd, 0, 1)) {
1984        TCGv s1;
1985        TCGLabel *over = gen_new_label();
1986        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1987
1988        s1 = get_gpr(s, a->rs1, EXT_SIGN);
1989
1990        if (s->vl_eq_vlmax) {
1991            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1992                                MAXSZ(s), MAXSZ(s), s1);
1993        } else {
1994            TCGv_i32 desc;
1995            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1996            TCGv_ptr dest = tcg_temp_new_ptr();
1997            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1998            static gen_helper_vmv_vx * const fns[4] = {
1999                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2000                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2001            };
2002
2003            tcg_gen_ext_tl_i64(s1_i64, s1);
2004            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2005            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2006            fns[s->sew](dest, s1_i64, cpu_env, desc);
2007
2008            tcg_temp_free_ptr(dest);
2009            tcg_temp_free_i64(s1_i64);
2010        }
2011
2012        mark_vs_dirty(s);
2013        gen_set_label(over);
2014        return true;
2015    }
2016    return false;
2017}
2018
2019static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
2020{
2021    if (require_rvv(s) &&
2022        vext_check_isa_ill(s) &&
2023        /* vmv.v.i has rs2 = 0 and vm = 1 */
2024        vext_check_ss(s, a->rd, 0, 1)) {
2025        int64_t simm = sextract64(a->rs1, 0, 5);
2026        if (s->vl_eq_vlmax) {
2027            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
2028                                 MAXSZ(s), MAXSZ(s), simm);
2029            mark_vs_dirty(s);
2030        } else {
2031            TCGv_i32 desc;
2032            TCGv_i64 s1;
2033            TCGv_ptr dest;
2034            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2035            static gen_helper_vmv_vx * const fns[4] = {
2036                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2037                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2038            };
2039            TCGLabel *over = gen_new_label();
2040            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2041
2042            s1 = tcg_constant_i64(simm);
2043            dest = tcg_temp_new_ptr();
2044            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2045            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2046            fns[s->sew](dest, s1, cpu_env, desc);
2047
2048            tcg_temp_free_ptr(dest);
2049            mark_vs_dirty(s);
2050            gen_set_label(over);
2051        }
2052        return true;
2053    }
2054    return false;
2055}
2056
2057GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
2058GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
2059GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
2060
2061/*
2062 *** Vector Fixed-Point Arithmetic Instructions
2063 */
2064
2065/* Vector Single-Width Saturating Add and Subtract */
2066GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
2067GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
2068GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
2069GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
2070GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
2071GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
2072GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
2073GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
2074GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check)
2075GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
2076
2077/* Vector Single-Width Averaging Add and Subtract */
2078GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
2079GEN_OPIVV_TRANS(vaaddu_vv, opivv_check)
2080GEN_OPIVV_TRANS(vasub_vv, opivv_check)
2081GEN_OPIVV_TRANS(vasubu_vv, opivv_check)
2082GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
2083GEN_OPIVX_TRANS(vaaddu_vx,  opivx_check)
2084GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
2085GEN_OPIVX_TRANS(vasubu_vx,  opivx_check)
2086
2087/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
2088GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
2089GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
2090
2091/* Vector Single-Width Scaling Shift Instructions */
2092GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
2093GEN_OPIVV_TRANS(vssra_vv, opivv_check)
2094GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
2095GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
2096GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check)
2097GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check)
2098
2099/* Vector Narrowing Fixed-Point Clip Instructions */
2100GEN_OPIWV_NARROW_TRANS(vnclipu_wv)
2101GEN_OPIWV_NARROW_TRANS(vnclip_wv)
2102GEN_OPIWX_NARROW_TRANS(vnclipu_wx)
2103GEN_OPIWX_NARROW_TRANS(vnclip_wx)
2104GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx)
2105GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx)
2106
2107/*
2108 *** Vector Float Point Arithmetic Instructions
2109 */
2110
2111/*
2112 * As RVF-only cpus always have values NaN-boxed to 64-bits,
2113 * RVF and RVD can be treated equally.
2114 * We don't have to deal with the cases of: SEW > FLEN.
2115 *
2116 * If SEW < FLEN, check whether input fp register is a valid
2117 * NaN-boxed value, in which case the least-significant SEW bits
2118 * of the f regsiter are used, else the canonical NaN value is used.
2119 */
2120static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
2121{
2122    switch (s->sew) {
2123    case 1:
2124        gen_check_nanbox_h(out, in);
2125        break;
2126    case 2:
2127        gen_check_nanbox_s(out, in);
2128        break;
2129    case 3:
2130        tcg_gen_mov_i64(out, in);
2131        break;
2132    default:
2133        g_assert_not_reached();
2134    }
2135}
2136
2137/* Vector Single-Width Floating-Point Add/Subtract Instructions */
2138
2139/*
2140 * If the current SEW does not correspond to a supported IEEE floating-point
2141 * type, an illegal instruction exception is raised.
2142 */
2143static bool opfvv_check(DisasContext *s, arg_rmrr *a)
2144{
2145    return require_rvv(s) &&
2146           require_rvf(s) &&
2147           vext_check_isa_ill(s) &&
2148           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
2149}
2150
2151/* OPFVV without GVEC IR */
2152#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2153static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2154{                                                                  \
2155    if (CHECK(s, a)) {                                             \
2156        uint32_t data = 0;                                         \
2157        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2158            gen_helper_##NAME##_h,                                 \
2159            gen_helper_##NAME##_w,                                 \
2160            gen_helper_##NAME##_d,                                 \
2161        };                                                         \
2162        TCGLabel *over = gen_new_label();                          \
2163        gen_set_rm(s, RISCV_FRM_DYN);                              \
2164        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2165                                                                   \
2166        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2167        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2168        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2169                           vreg_ofs(s, a->rs1),                    \
2170                           vreg_ofs(s, a->rs2), cpu_env,           \
2171                           s->vlen / 8, s->vlen / 8, data,         \
2172                           fns[s->sew - 1]);                       \
2173        mark_vs_dirty(s);                                          \
2174        gen_set_label(over);                                       \
2175        return true;                                               \
2176    }                                                              \
2177    return false;                                                  \
2178}
2179GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2180GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2181
2182typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2183                              TCGv_env, TCGv_i32);
2184
2185static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2186                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2187{
2188    TCGv_ptr dest, src2, mask;
2189    TCGv_i32 desc;
2190    TCGv_i64 t1;
2191
2192    TCGLabel *over = gen_new_label();
2193    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2194
2195    dest = tcg_temp_new_ptr();
2196    mask = tcg_temp_new_ptr();
2197    src2 = tcg_temp_new_ptr();
2198    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2199
2200    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2201    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2202    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2203
2204    /* NaN-box f[rs1] */
2205    t1 = tcg_temp_new_i64();
2206    do_nanbox(s, t1, cpu_fpr[rs1]);
2207
2208    fn(dest, mask, t1, src2, cpu_env, desc);
2209
2210    tcg_temp_free_ptr(dest);
2211    tcg_temp_free_ptr(mask);
2212    tcg_temp_free_ptr(src2);
2213    tcg_temp_free_i64(t1);
2214    mark_vs_dirty(s);
2215    gen_set_label(over);
2216    return true;
2217}
2218
2219/*
2220 * If the current SEW does not correspond to a supported IEEE floating-point
2221 * type, an illegal instruction exception is raised
2222 */
2223static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2224{
2225    return require_rvv(s) &&
2226           require_rvf(s) &&
2227           vext_check_isa_ill(s) &&
2228           vext_check_ss(s, a->rd, a->rs2, a->vm);
2229}
2230
2231/* OPFVF without GVEC IR */
2232#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2233static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2234{                                                                 \
2235    if (CHECK(s, a)) {                                            \
2236        uint32_t data = 0;                                        \
2237        static gen_helper_opfvf *const fns[3] = {                 \
2238            gen_helper_##NAME##_h,                                \
2239            gen_helper_##NAME##_w,                                \
2240            gen_helper_##NAME##_d,                                \
2241        };                                                        \
2242        gen_set_rm(s, RISCV_FRM_DYN);                             \
2243        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2244        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2245        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2246                           fns[s->sew - 1], s);                   \
2247    }                                                             \
2248    return false;                                                 \
2249}
2250
2251GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2252GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2253GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2254
2255/* Vector Widening Floating-Point Add/Subtract Instructions */
2256static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2257{
2258    return require_rvv(s) &&
2259           require_scale_rvf(s) &&
2260           (s->sew != MO_8) &&
2261           vext_check_isa_ill(s) &&
2262           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2263}
2264
2265/* OPFVV with WIDEN */
2266#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2267static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2268{                                                                \
2269    if (CHECK(s, a)) {                                           \
2270        uint32_t data = 0;                                       \
2271        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2272            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2273        };                                                       \
2274        TCGLabel *over = gen_new_label();                        \
2275        gen_set_rm(s, RISCV_FRM_DYN);                            \
2276        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2277                                                                 \
2278        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2279        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2280        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2281                           vreg_ofs(s, a->rs1),                  \
2282                           vreg_ofs(s, a->rs2), cpu_env,         \
2283                           s->vlen / 8, s->vlen / 8, data,       \
2284                           fns[s->sew - 1]);                     \
2285        mark_vs_dirty(s);                                        \
2286        gen_set_label(over);                                     \
2287        return true;                                             \
2288    }                                                            \
2289    return false;                                                \
2290}
2291
2292GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2293GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2294
2295static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2296{
2297    return require_rvv(s) &&
2298           require_scale_rvf(s) &&
2299           (s->sew != MO_8) &&
2300           vext_check_isa_ill(s) &&
2301           vext_check_ds(s, a->rd, a->rs2, a->vm);
2302}
2303
2304/* OPFVF with WIDEN */
2305#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2306static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2307{                                                                \
2308    if (opfvf_widen_check(s, a)) {                               \
2309        uint32_t data = 0;                                       \
2310        static gen_helper_opfvf *const fns[2] = {                \
2311            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2312        };                                                       \
2313        gen_set_rm(s, RISCV_FRM_DYN);                            \
2314        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2315        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2316        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2317                           fns[s->sew - 1], s);                  \
2318    }                                                            \
2319    return false;                                                \
2320}
2321
2322GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2323GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2324
2325static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2326{
2327    return require_rvv(s) &&
2328           require_scale_rvf(s) &&
2329           (s->sew != MO_8) &&
2330           vext_check_isa_ill(s) &&
2331           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2332}
2333
2334/* WIDEN OPFVV with WIDEN */
2335#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2336static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2337{                                                                  \
2338    if (opfwv_widen_check(s, a)) {                                 \
2339        uint32_t data = 0;                                         \
2340        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2341            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2342        };                                                         \
2343        TCGLabel *over = gen_new_label();                          \
2344        gen_set_rm(s, RISCV_FRM_DYN);                              \
2345        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2346                                                                   \
2347        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2348        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2349        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2350                           vreg_ofs(s, a->rs1),                    \
2351                           vreg_ofs(s, a->rs2), cpu_env,           \
2352                           s->vlen / 8, s->vlen / 8, data,         \
2353                           fns[s->sew - 1]);                       \
2354        mark_vs_dirty(s);                                          \
2355        gen_set_label(over);                                       \
2356        return true;                                               \
2357    }                                                              \
2358    return false;                                                  \
2359}
2360
2361GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2362GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2363
2364static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2365{
2366    return require_rvv(s) &&
2367           require_scale_rvf(s) &&
2368           (s->sew != MO_8) &&
2369           vext_check_isa_ill(s) &&
2370           vext_check_dd(s, a->rd, a->rs2, a->vm);
2371}
2372
2373/* WIDEN OPFVF with WIDEN */
2374#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2375static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2376{                                                                \
2377    if (opfwf_widen_check(s, a)) {                               \
2378        uint32_t data = 0;                                       \
2379        static gen_helper_opfvf *const fns[2] = {                \
2380            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2381        };                                                       \
2382        gen_set_rm(s, RISCV_FRM_DYN);                            \
2383        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2384        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2385        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2386                           fns[s->sew - 1], s);                  \
2387    }                                                            \
2388    return false;                                                \
2389}
2390
2391GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2392GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2393
2394/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2395GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2396GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2397GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2398GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2399GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2400
2401/* Vector Widening Floating-Point Multiply */
2402GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2403GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2404
2405/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2406GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2407GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2408GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2409GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2410GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2411GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2412GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2413GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2414GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2415GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2416GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2417GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2418GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2419GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2420GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2421GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2422
2423/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2424GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2425GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2426GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2427GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2428GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2429GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2430GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2431GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2432
2433/* Vector Floating-Point Square-Root Instruction */
2434
2435/*
2436 * If the current SEW does not correspond to a supported IEEE floating-point
2437 * type, an illegal instruction exception is raised
2438 */
2439static bool opfv_check(DisasContext *s, arg_rmr *a)
2440{
2441    return require_rvv(s) &&
2442           require_rvf(s) &&
2443           vext_check_isa_ill(s) &&
2444           /* OPFV instructions ignore vs1 check */
2445           vext_check_ss(s, a->rd, a->rs2, a->vm);
2446}
2447
2448static bool do_opfv(DisasContext *s, arg_rmr *a,
2449                    gen_helper_gvec_3_ptr *fn,
2450                    bool (*checkfn)(DisasContext *, arg_rmr *),
2451                    int rm)
2452{
2453    if (checkfn(s, a)) {
2454        if (rm != RISCV_FRM_DYN) {
2455            gen_set_rm(s, RISCV_FRM_DYN);
2456        }
2457
2458        uint32_t data = 0;
2459        TCGLabel *over = gen_new_label();
2460        gen_set_rm(s, rm);
2461        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2462
2463        data = FIELD_DP32(data, VDATA, VM, a->vm);
2464        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2465        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2466                           vreg_ofs(s, a->rs2), cpu_env,
2467                           s->vlen / 8, s->vlen / 8, data, fn);
2468        mark_vs_dirty(s);
2469        gen_set_label(over);
2470        return true;
2471    }
2472    return false;
2473}
2474
2475#define GEN_OPFV_TRANS(NAME, CHECK, FRM)               \
2476static bool trans_##NAME(DisasContext *s, arg_rmr *a)  \
2477{                                                      \
2478    static gen_helper_gvec_3_ptr * const fns[3] = {    \
2479        gen_helper_##NAME##_h,                         \
2480        gen_helper_##NAME##_w,                         \
2481        gen_helper_##NAME##_d                          \
2482    };                                                 \
2483    return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \
2484}
2485
2486GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN)
2487GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN)
2488GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN)
2489
2490/* Vector Floating-Point MIN/MAX Instructions */
2491GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2492GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2493GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2494GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2495
2496/* Vector Floating-Point Sign-Injection Instructions */
2497GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2498GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2499GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2500GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2501GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2502GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2503
2504/* Vector Floating-Point Compare Instructions */
2505static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2506{
2507    return require_rvv(s) &&
2508           require_rvf(s) &&
2509           vext_check_isa_ill(s) &&
2510           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2511}
2512
2513GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2514GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2515GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2516GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2517
2518static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2519{
2520    return require_rvv(s) &&
2521           require_rvf(s) &&
2522           vext_check_isa_ill(s) &&
2523           vext_check_ms(s, a->rd, a->rs2);
2524}
2525
2526GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2527GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2528GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2529GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2530GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2531GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2532
2533/* Vector Floating-Point Classify Instruction */
2534GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN)
2535
2536/* Vector Floating-Point Merge Instruction */
2537GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2538
2539static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2540{
2541    if (require_rvv(s) &&
2542        require_rvf(s) &&
2543        vext_check_isa_ill(s) &&
2544        require_align(a->rd, s->lmul)) {
2545        gen_set_rm(s, RISCV_FRM_DYN);
2546
2547        TCGv_i64 t1;
2548
2549        if (s->vl_eq_vlmax) {
2550            t1 = tcg_temp_new_i64();
2551            /* NaN-box f[rs1] */
2552            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2553
2554            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2555                                 MAXSZ(s), MAXSZ(s), t1);
2556            mark_vs_dirty(s);
2557        } else {
2558            TCGv_ptr dest;
2559            TCGv_i32 desc;
2560            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2561            static gen_helper_vmv_vx * const fns[3] = {
2562                gen_helper_vmv_v_x_h,
2563                gen_helper_vmv_v_x_w,
2564                gen_helper_vmv_v_x_d,
2565            };
2566            TCGLabel *over = gen_new_label();
2567            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2568
2569            t1 = tcg_temp_new_i64();
2570            /* NaN-box f[rs1] */
2571            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2572
2573            dest = tcg_temp_new_ptr();
2574            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2575            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2576
2577            fns[s->sew - 1](dest, t1, cpu_env, desc);
2578
2579            tcg_temp_free_ptr(dest);
2580            mark_vs_dirty(s);
2581            gen_set_label(over);
2582        }
2583        tcg_temp_free_i64(t1);
2584        return true;
2585    }
2586    return false;
2587}
2588
2589/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2590#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM)               \
2591static bool trans_##NAME(DisasContext *s, arg_rmr *a)       \
2592{                                                           \
2593    static gen_helper_gvec_3_ptr * const fns[3] = {         \
2594        gen_helper_##HELPER##_h,                            \
2595        gen_helper_##HELPER##_w,                            \
2596        gen_helper_##HELPER##_d                             \
2597    };                                                      \
2598    return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \
2599}
2600
2601GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN)
2602GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN)
2603GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN)
2604GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN)
2605/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */
2606GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ)
2607GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ)
2608
2609/* Widening Floating-Point/Integer Type-Convert Instructions */
2610
2611/*
2612 * If the current SEW does not correspond to a supported IEEE floating-point
2613 * type, an illegal instruction exception is raised
2614 */
2615static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2616{
2617    return require_rvv(s) &&
2618           vext_check_isa_ill(s) &&
2619           vext_check_ds(s, a->rd, a->rs2, a->vm);
2620}
2621
2622static bool opxfv_widen_check(DisasContext *s, arg_rmr *a)
2623{
2624    return opfv_widen_check(s, a) &&
2625           require_rvf(s);
2626}
2627
2628static bool opffv_widen_check(DisasContext *s, arg_rmr *a)
2629{
2630    return opfv_widen_check(s, a) &&
2631           require_scale_rvf(s) &&
2632           (s->sew != MO_8);
2633}
2634
2635#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM)             \
2636static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2637{                                                                  \
2638    if (CHECK(s, a)) {                                             \
2639        if (FRM != RISCV_FRM_DYN) {                                \
2640            gen_set_rm(s, RISCV_FRM_DYN);                          \
2641        }                                                          \
2642                                                                   \
2643        uint32_t data = 0;                                         \
2644        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2645            gen_helper_##HELPER##_h,                               \
2646            gen_helper_##HELPER##_w,                               \
2647        };                                                         \
2648        TCGLabel *over = gen_new_label();                          \
2649        gen_set_rm(s, FRM);                                        \
2650        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2651                                                                   \
2652        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2653        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2654        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2655                           vreg_ofs(s, a->rs2), cpu_env,           \
2656                           s->vlen / 8, s->vlen / 8, data,         \
2657                           fns[s->sew - 1]);                       \
2658        mark_vs_dirty(s);                                          \
2659        gen_set_label(over);                                       \
2660        return true;                                               \
2661    }                                                              \
2662    return false;                                                  \
2663}
2664
2665GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2666                     RISCV_FRM_DYN)
2667GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2668                     RISCV_FRM_DYN)
2669GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v,
2670                     RISCV_FRM_DYN)
2671/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */
2672GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2673                     RISCV_FRM_RTZ)
2674GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2675                     RISCV_FRM_RTZ)
2676
2677static bool opfxv_widen_check(DisasContext *s, arg_rmr *a)
2678{
2679    return require_rvv(s) &&
2680           require_scale_rvf(s) &&
2681           vext_check_isa_ill(s) &&
2682           /* OPFV widening instructions ignore vs1 check */
2683           vext_check_ds(s, a->rd, a->rs2, a->vm);
2684}
2685
2686#define GEN_OPFXV_WIDEN_TRANS(NAME)                                \
2687static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2688{                                                                  \
2689    if (opfxv_widen_check(s, a)) {                                 \
2690        uint32_t data = 0;                                         \
2691        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2692            gen_helper_##NAME##_b,                                 \
2693            gen_helper_##NAME##_h,                                 \
2694            gen_helper_##NAME##_w,                                 \
2695        };                                                         \
2696        TCGLabel *over = gen_new_label();                          \
2697        gen_set_rm(s, RISCV_FRM_DYN);                              \
2698        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2699                                                                   \
2700        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2701        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2702                           vreg_ofs(s, a->rs2), cpu_env,           \
2703                           s->vlen / 8, s->vlen / 8, data,         \
2704                           fns[s->sew]);                           \
2705        mark_vs_dirty(s);                                          \
2706        gen_set_label(over);                                       \
2707        return true;                                               \
2708    }                                                              \
2709    return false;                                                  \
2710}
2711
2712GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v)
2713GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v)
2714
2715/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2716
2717/*
2718 * If the current SEW does not correspond to a supported IEEE floating-point
2719 * type, an illegal instruction exception is raised
2720 */
2721static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2722{
2723    return require_rvv(s) &&
2724           vext_check_isa_ill(s) &&
2725           /* OPFV narrowing instructions ignore vs1 check */
2726           vext_check_sd(s, a->rd, a->rs2, a->vm);
2727}
2728
2729static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a)
2730{
2731    return opfv_narrow_check(s, a) &&
2732           require_rvf(s) &&
2733           (s->sew != MO_64);
2734}
2735
2736static bool opffv_narrow_check(DisasContext *s, arg_rmr *a)
2737{
2738    return opfv_narrow_check(s, a) &&
2739           require_scale_rvf(s) &&
2740           (s->sew != MO_8);
2741}
2742
2743#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM)            \
2744static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2745{                                                                  \
2746    if (CHECK(s, a)) {                                             \
2747        if (FRM != RISCV_FRM_DYN) {                                \
2748            gen_set_rm(s, RISCV_FRM_DYN);                          \
2749        }                                                          \
2750                                                                   \
2751        uint32_t data = 0;                                         \
2752        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2753            gen_helper_##HELPER##_h,                               \
2754            gen_helper_##HELPER##_w,                               \
2755        };                                                         \
2756        TCGLabel *over = gen_new_label();                          \
2757        gen_set_rm(s, FRM);                                        \
2758        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2759                                                                   \
2760        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2761        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2762        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2763                           vreg_ofs(s, a->rs2), cpu_env,           \
2764                           s->vlen / 8, s->vlen / 8, data,         \
2765                           fns[s->sew - 1]);                       \
2766        mark_vs_dirty(s);                                          \
2767        gen_set_label(over);                                       \
2768        return true;                                               \
2769    }                                                              \
2770    return false;                                                  \
2771}
2772
2773GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w,
2774                      RISCV_FRM_DYN)
2775GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w,
2776                      RISCV_FRM_DYN)
2777GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
2778                      RISCV_FRM_DYN)
2779/* Reuse the helper function from vfncvt.f.f.w */
2780GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
2781                      RISCV_FRM_ROD)
2782
2783static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a)
2784{
2785    return require_rvv(s) &&
2786           require_scale_rvf(s) &&
2787           vext_check_isa_ill(s) &&
2788           /* OPFV narrowing instructions ignore vs1 check */
2789           vext_check_sd(s, a->rd, a->rs2, a->vm);
2790}
2791
2792#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM)                  \
2793static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2794{                                                                  \
2795    if (opxfv_narrow_check(s, a)) {                                \
2796        if (FRM != RISCV_FRM_DYN) {                                \
2797            gen_set_rm(s, RISCV_FRM_DYN);                          \
2798        }                                                          \
2799                                                                   \
2800        uint32_t data = 0;                                         \
2801        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2802            gen_helper_##HELPER##_b,                               \
2803            gen_helper_##HELPER##_h,                               \
2804            gen_helper_##HELPER##_w,                               \
2805        };                                                         \
2806        TCGLabel *over = gen_new_label();                          \
2807        gen_set_rm(s, FRM);                                        \
2808        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2809                                                                   \
2810        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2811        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2812                           vreg_ofs(s, a->rs2), cpu_env,           \
2813                           s->vlen / 8, s->vlen / 8, data,         \
2814                           fns[s->sew]);                           \
2815        mark_vs_dirty(s);                                          \
2816        gen_set_label(over);                                       \
2817        return true;                                               \
2818    }                                                              \
2819    return false;                                                  \
2820}
2821
2822GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN)
2823GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN)
2824/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */
2825GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ)
2826GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ)
2827
2828/*
2829 *** Vector Reduction Operations
2830 */
2831/* Vector Single-Width Integer Reduction Instructions */
2832static bool reduction_check(DisasContext *s, arg_rmrr *a)
2833{
2834    return require_rvv(s) &&
2835           vext_check_isa_ill(s) &&
2836           vext_check_reduction(s, a->rs2);
2837}
2838
2839GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2840GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2841GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2842GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2843GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2844GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2845GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2846GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2847
2848/* Vector Widening Integer Reduction Instructions */
2849static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
2850{
2851    return reduction_check(s, a) && (s->sew < MO_64) &&
2852           ((s->sew + 1) <= (s->elen >> 4));
2853}
2854
2855GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
2856GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
2857
2858/* Vector Single-Width Floating-Point Reduction Instructions */
2859static bool freduction_check(DisasContext *s, arg_rmrr *a)
2860{
2861    return reduction_check(s, a) &&
2862           require_rvf(s);
2863}
2864
2865GEN_OPFVV_TRANS(vfredsum_vs, freduction_check)
2866GEN_OPFVV_TRANS(vfredmax_vs, freduction_check)
2867GEN_OPFVV_TRANS(vfredmin_vs, freduction_check)
2868
2869/* Vector Widening Floating-Point Reduction Instructions */
2870static bool freduction_widen_check(DisasContext *s, arg_rmrr *a)
2871{
2872    return reduction_widen_check(s, a) &&
2873           require_scale_rvf(s) &&
2874           (s->sew != MO_8);
2875}
2876
2877GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check)
2878
2879/*
2880 *** Vector Mask Operations
2881 */
2882
2883/* Vector Mask-Register Logical Instructions */
2884#define GEN_MM_TRANS(NAME)                                         \
2885static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2886{                                                                  \
2887    if (require_rvv(s) &&                                          \
2888        vext_check_isa_ill(s)) {                                   \
2889        uint32_t data = 0;                                         \
2890        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2891        TCGLabel *over = gen_new_label();                          \
2892        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2893                                                                   \
2894        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2895        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2896                           vreg_ofs(s, a->rs1),                    \
2897                           vreg_ofs(s, a->rs2), cpu_env,           \
2898                           s->vlen / 8, s->vlen / 8, data, fn);    \
2899        mark_vs_dirty(s);                                          \
2900        gen_set_label(over);                                       \
2901        return true;                                               \
2902    }                                                              \
2903    return false;                                                  \
2904}
2905
2906GEN_MM_TRANS(vmand_mm)
2907GEN_MM_TRANS(vmnand_mm)
2908GEN_MM_TRANS(vmandn_mm)
2909GEN_MM_TRANS(vmxor_mm)
2910GEN_MM_TRANS(vmor_mm)
2911GEN_MM_TRANS(vmnor_mm)
2912GEN_MM_TRANS(vmorn_mm)
2913GEN_MM_TRANS(vmxnor_mm)
2914
2915/* Vector count population in mask vcpop */
2916static bool trans_vcpop_m(DisasContext *s, arg_rmr *a)
2917{
2918    if (require_rvv(s) &&
2919        vext_check_isa_ill(s) &&
2920        s->vstart == 0) {
2921        TCGv_ptr src2, mask;
2922        TCGv dst;
2923        TCGv_i32 desc;
2924        uint32_t data = 0;
2925        data = FIELD_DP32(data, VDATA, VM, a->vm);
2926        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2927
2928        mask = tcg_temp_new_ptr();
2929        src2 = tcg_temp_new_ptr();
2930        dst = dest_gpr(s, a->rd);
2931        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2932
2933        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2934        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2935
2936        gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc);
2937        gen_set_gpr(s, a->rd, dst);
2938
2939        tcg_temp_free_ptr(mask);
2940        tcg_temp_free_ptr(src2);
2941
2942        return true;
2943    }
2944    return false;
2945}
2946
2947/* vmfirst find-first-set mask bit */
2948static bool trans_vfirst_m(DisasContext *s, arg_rmr *a)
2949{
2950    if (require_rvv(s) &&
2951        vext_check_isa_ill(s) &&
2952        s->vstart == 0) {
2953        TCGv_ptr src2, mask;
2954        TCGv dst;
2955        TCGv_i32 desc;
2956        uint32_t data = 0;
2957        data = FIELD_DP32(data, VDATA, VM, a->vm);
2958        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2959
2960        mask = tcg_temp_new_ptr();
2961        src2 = tcg_temp_new_ptr();
2962        dst = dest_gpr(s, a->rd);
2963        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2964
2965        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2966        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2967
2968        gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc);
2969        gen_set_gpr(s, a->rd, dst);
2970
2971        tcg_temp_free_ptr(mask);
2972        tcg_temp_free_ptr(src2);
2973        return true;
2974    }
2975    return false;
2976}
2977
2978/* vmsbf.m set-before-first mask bit */
2979/* vmsif.m set-includ-first mask bit */
2980/* vmsof.m set-only-first mask bit */
2981#define GEN_M_TRANS(NAME)                                          \
2982static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2983{                                                                  \
2984    if (require_rvv(s) &&                                          \
2985        vext_check_isa_ill(s) &&                                   \
2986        require_vm(a->vm, a->rd) &&                                \
2987        (a->rd != a->rs2) &&                                       \
2988        (s->vstart == 0)) {                                        \
2989        uint32_t data = 0;                                         \
2990        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2991        TCGLabel *over = gen_new_label();                          \
2992        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2993                                                                   \
2994        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2995        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2996        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2997                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2998                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2999                           data, fn);                              \
3000        mark_vs_dirty(s);                                          \
3001        gen_set_label(over);                                       \
3002        return true;                                               \
3003    }                                                              \
3004    return false;                                                  \
3005}
3006
3007GEN_M_TRANS(vmsbf_m)
3008GEN_M_TRANS(vmsif_m)
3009GEN_M_TRANS(vmsof_m)
3010
3011/*
3012 * Vector Iota Instruction
3013 *
3014 * 1. The destination register cannot overlap the source register.
3015 * 2. If masked, cannot overlap the mask register ('v0').
3016 * 3. An illegal instruction exception is raised if vstart is non-zero.
3017 */
3018static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
3019{
3020    if (require_rvv(s) &&
3021        vext_check_isa_ill(s) &&
3022        !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) &&
3023        require_vm(a->vm, a->rd) &&
3024        require_align(a->rd, s->lmul) &&
3025        (s->vstart == 0)) {
3026        uint32_t data = 0;
3027        TCGLabel *over = gen_new_label();
3028        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3029
3030        data = FIELD_DP32(data, VDATA, VM, a->vm);
3031        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3032        static gen_helper_gvec_3_ptr * const fns[4] = {
3033            gen_helper_viota_m_b, gen_helper_viota_m_h,
3034            gen_helper_viota_m_w, gen_helper_viota_m_d,
3035        };
3036        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3037                           vreg_ofs(s, a->rs2), cpu_env,
3038                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
3039        mark_vs_dirty(s);
3040        gen_set_label(over);
3041        return true;
3042    }
3043    return false;
3044}
3045
3046/* Vector Element Index Instruction */
3047static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
3048{
3049    if (require_rvv(s) &&
3050        vext_check_isa_ill(s) &&
3051        require_align(a->rd, s->lmul) &&
3052        require_vm(a->vm, a->rd)) {
3053        uint32_t data = 0;
3054        TCGLabel *over = gen_new_label();
3055        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3056
3057        data = FIELD_DP32(data, VDATA, VM, a->vm);
3058        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3059        static gen_helper_gvec_2_ptr * const fns[4] = {
3060            gen_helper_vid_v_b, gen_helper_vid_v_h,
3061            gen_helper_vid_v_w, gen_helper_vid_v_d,
3062        };
3063        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3064                           cpu_env, s->vlen / 8, s->vlen / 8,
3065                           data, fns[s->sew]);
3066        mark_vs_dirty(s);
3067        gen_set_label(over);
3068        return true;
3069    }
3070    return false;
3071}
3072
3073/*
3074 *** Vector Permutation Instructions
3075 */
3076
3077static void load_element(TCGv_i64 dest, TCGv_ptr base,
3078                         int ofs, int sew, bool sign)
3079{
3080    switch (sew) {
3081    case MO_8:
3082        if (!sign) {
3083            tcg_gen_ld8u_i64(dest, base, ofs);
3084        } else {
3085            tcg_gen_ld8s_i64(dest, base, ofs);
3086        }
3087        break;
3088    case MO_16:
3089        if (!sign) {
3090            tcg_gen_ld16u_i64(dest, base, ofs);
3091        } else {
3092            tcg_gen_ld16s_i64(dest, base, ofs);
3093        }
3094        break;
3095    case MO_32:
3096        if (!sign) {
3097            tcg_gen_ld32u_i64(dest, base, ofs);
3098        } else {
3099            tcg_gen_ld32s_i64(dest, base, ofs);
3100        }
3101        break;
3102    case MO_64:
3103        tcg_gen_ld_i64(dest, base, ofs);
3104        break;
3105    default:
3106        g_assert_not_reached();
3107        break;
3108    }
3109}
3110
3111/* offset of the idx element with base regsiter r */
3112static uint32_t endian_ofs(DisasContext *s, int r, int idx)
3113{
3114#ifdef HOST_WORDS_BIGENDIAN
3115    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
3116#else
3117    return vreg_ofs(s, r) + (idx << s->sew);
3118#endif
3119}
3120
3121/* adjust the index according to the endian */
3122static void endian_adjust(TCGv_i32 ofs, int sew)
3123{
3124#ifdef HOST_WORDS_BIGENDIAN
3125    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
3126#endif
3127}
3128
3129/* Load idx >= VLMAX ? 0 : vreg[idx] */
3130static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
3131                              int vreg, TCGv idx, int vlmax)
3132{
3133    TCGv_i32 ofs = tcg_temp_new_i32();
3134    TCGv_ptr base = tcg_temp_new_ptr();
3135    TCGv_i64 t_idx = tcg_temp_new_i64();
3136    TCGv_i64 t_vlmax, t_zero;
3137
3138    /*
3139     * Mask the index to the length so that we do
3140     * not produce an out-of-range load.
3141     */
3142    tcg_gen_trunc_tl_i32(ofs, idx);
3143    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
3144
3145    /* Convert the index to an offset. */
3146    endian_adjust(ofs, s->sew);
3147    tcg_gen_shli_i32(ofs, ofs, s->sew);
3148
3149    /* Convert the index to a pointer. */
3150    tcg_gen_ext_i32_ptr(base, ofs);
3151    tcg_gen_add_ptr(base, base, cpu_env);
3152
3153    /* Perform the load. */
3154    load_element(dest, base,
3155                 vreg_ofs(s, vreg), s->sew, false);
3156    tcg_temp_free_ptr(base);
3157    tcg_temp_free_i32(ofs);
3158
3159    /* Flush out-of-range indexing to zero.  */
3160    t_vlmax = tcg_constant_i64(vlmax);
3161    t_zero = tcg_constant_i64(0);
3162    tcg_gen_extu_tl_i64(t_idx, idx);
3163
3164    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
3165                        t_vlmax, dest, t_zero);
3166
3167    tcg_temp_free_i64(t_idx);
3168}
3169
3170static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
3171                              int vreg, int idx, bool sign)
3172{
3173    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign);
3174}
3175
3176/* Integer Scalar Move Instruction */
3177
3178static void store_element(TCGv_i64 val, TCGv_ptr base,
3179                          int ofs, int sew)
3180{
3181    switch (sew) {
3182    case MO_8:
3183        tcg_gen_st8_i64(val, base, ofs);
3184        break;
3185    case MO_16:
3186        tcg_gen_st16_i64(val, base, ofs);
3187        break;
3188    case MO_32:
3189        tcg_gen_st32_i64(val, base, ofs);
3190        break;
3191    case MO_64:
3192        tcg_gen_st_i64(val, base, ofs);
3193        break;
3194    default:
3195        g_assert_not_reached();
3196        break;
3197    }
3198}
3199
3200/*
3201 * Store vreg[idx] = val.
3202 * The index must be in range of VLMAX.
3203 */
3204static void vec_element_storei(DisasContext *s, int vreg,
3205                               int idx, TCGv_i64 val)
3206{
3207    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
3208}
3209
3210/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */
3211static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a)
3212{
3213    if (require_rvv(s) &&
3214        vext_check_isa_ill(s)) {
3215        TCGv_i64 t1;
3216        TCGv dest;
3217
3218        t1 = tcg_temp_new_i64();
3219        dest = tcg_temp_new();
3220        /*
3221         * load vreg and sign-extend to 64 bits,
3222         * then truncate to XLEN bits before storing to gpr.
3223         */
3224        vec_element_loadi(s, t1, a->rs2, 0, true);
3225        tcg_gen_trunc_i64_tl(dest, t1);
3226        gen_set_gpr(s, a->rd, dest);
3227        tcg_temp_free_i64(t1);
3228        tcg_temp_free(dest);
3229
3230        return true;
3231    }
3232    return false;
3233}
3234
3235/* vmv.s.x vd, rs1 # vd[0] = rs1 */
3236static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
3237{
3238    if (require_rvv(s) &&
3239        vext_check_isa_ill(s)) {
3240        /* This instruction ignores LMUL and vector register groups */
3241        TCGv_i64 t1;
3242        TCGv s1;
3243        TCGLabel *over = gen_new_label();
3244
3245        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3246        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3247
3248        t1 = tcg_temp_new_i64();
3249
3250        /*
3251         * load gpr and sign-extend to 64 bits,
3252         * then truncate to SEW bits when storing to vreg.
3253         */
3254        s1 = get_gpr(s, a->rs1, EXT_NONE);
3255        tcg_gen_ext_tl_i64(t1, s1);
3256        vec_element_storei(s, a->rd, 0, t1);
3257        tcg_temp_free_i64(t1);
3258        mark_vs_dirty(s);
3259        gen_set_label(over);
3260        return true;
3261    }
3262    return false;
3263}
3264
3265/* Floating-Point Scalar Move Instructions */
3266static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
3267{
3268    if (require_rvv(s) &&
3269        require_rvf(s) &&
3270        vext_check_isa_ill(s)) {
3271        gen_set_rm(s, RISCV_FRM_DYN);
3272
3273        unsigned int ofs = (8 << s->sew);
3274        unsigned int len = 64 - ofs;
3275        TCGv_i64 t_nan;
3276
3277        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false);
3278        /* NaN-box f[rd] as necessary for SEW */
3279        if (len) {
3280            t_nan = tcg_constant_i64(UINT64_MAX);
3281            tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
3282                                t_nan, ofs, len);
3283        }
3284
3285        mark_fs_dirty(s);
3286        return true;
3287    }
3288    return false;
3289}
3290
3291/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
3292static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
3293{
3294    if (require_rvv(s) &&
3295        require_rvf(s) &&
3296        vext_check_isa_ill(s)) {
3297        gen_set_rm(s, RISCV_FRM_DYN);
3298
3299        /* The instructions ignore LMUL and vector register group. */
3300        TCGv_i64 t1;
3301        TCGLabel *over = gen_new_label();
3302
3303        /* if vl == 0 or vstart >= vl, skip vector register write back */
3304        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3305        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3306
3307        /* NaN-box f[rs1] */
3308        t1 = tcg_temp_new_i64();
3309        do_nanbox(s, t1, cpu_fpr[a->rs1]);
3310
3311        vec_element_storei(s, a->rd, 0, t1);
3312        tcg_temp_free_i64(t1);
3313        mark_vs_dirty(s);
3314        gen_set_label(over);
3315        return true;
3316    }
3317    return false;
3318}
3319
3320/* Vector Slide Instructions */
3321static bool slideup_check(DisasContext *s, arg_rmrr *a)
3322{
3323    return require_rvv(s) &&
3324           vext_check_isa_ill(s) &&
3325           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
3326}
3327
3328GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
3329GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
3330GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
3331
3332static bool slidedown_check(DisasContext *s, arg_rmrr *a)
3333{
3334    return require_rvv(s) &&
3335           vext_check_isa_ill(s) &&
3336           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
3337}
3338
3339GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
3340GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
3341GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
3342
3343/* Vector Floating-Point Slide Instructions */
3344static bool fslideup_check(DisasContext *s, arg_rmrr *a)
3345{
3346    return slideup_check(s, a) &&
3347           require_rvf(s);
3348}
3349
3350static bool fslidedown_check(DisasContext *s, arg_rmrr *a)
3351{
3352    return slidedown_check(s, a) &&
3353           require_rvf(s);
3354}
3355
3356GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check)
3357GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check)
3358
3359/* Vector Register Gather Instruction */
3360static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
3361{
3362    return require_rvv(s) &&
3363           vext_check_isa_ill(s) &&
3364           require_align(a->rd, s->lmul) &&
3365           require_align(a->rs1, s->lmul) &&
3366           require_align(a->rs2, s->lmul) &&
3367           (a->rd != a->rs2 && a->rd != a->rs1) &&
3368           require_vm(a->vm, a->rd);
3369}
3370
3371static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a)
3372{
3373    int8_t emul = MO_16 - s->sew + s->lmul;
3374    return require_rvv(s) &&
3375           vext_check_isa_ill(s) &&
3376           (emul >= -3 && emul <= 3) &&
3377           require_align(a->rd, s->lmul) &&
3378           require_align(a->rs1, emul) &&
3379           require_align(a->rs2, s->lmul) &&
3380           (a->rd != a->rs2 && a->rd != a->rs1) &&
3381           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3382                          a->rs1, 1 << MAX(emul, 0)) &&
3383           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3384                          a->rs2, 1 << MAX(s->lmul, 0)) &&
3385           require_vm(a->vm, a->rd);
3386}
3387
3388GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
3389GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check)
3390
3391static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
3392{
3393    return require_rvv(s) &&
3394           vext_check_isa_ill(s) &&
3395           require_align(a->rd, s->lmul) &&
3396           require_align(a->rs2, s->lmul) &&
3397           (a->rd != a->rs2) &&
3398           require_vm(a->vm, a->rd);
3399}
3400
3401/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3402static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3403{
3404    if (!vrgather_vx_check(s, a)) {
3405        return false;
3406    }
3407
3408    if (a->vm && s->vl_eq_vlmax) {
3409        int scale = s->lmul - (s->sew + 3);
3410        int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale;
3411        TCGv_i64 dest = tcg_temp_new_i64();
3412
3413        if (a->rs1 == 0) {
3414            vec_element_loadi(s, dest, a->rs2, 0, false);
3415        } else {
3416            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3417        }
3418
3419        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3420                             MAXSZ(s), MAXSZ(s), dest);
3421        tcg_temp_free_i64(dest);
3422        mark_vs_dirty(s);
3423    } else {
3424        static gen_helper_opivx * const fns[4] = {
3425            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3426            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3427        };
3428        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3429    }
3430    return true;
3431}
3432
3433/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3434static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3435{
3436    if (!vrgather_vx_check(s, a)) {
3437        return false;
3438    }
3439
3440    if (a->vm && s->vl_eq_vlmax) {
3441        int scale = s->lmul - (s->sew + 3);
3442        int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale;
3443        if (a->rs1 >= vlmax) {
3444            tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd),
3445                                 MAXSZ(s), MAXSZ(s), 0);
3446        } else {
3447            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3448                                 endian_ofs(s, a->rs2, a->rs1),
3449                                 MAXSZ(s), MAXSZ(s));
3450        }
3451        mark_vs_dirty(s);
3452    } else {
3453        static gen_helper_opivx * const fns[4] = {
3454            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3455            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3456        };
3457        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3458                           s, IMM_ZX);
3459    }
3460    return true;
3461}
3462
3463/*
3464 * Vector Compress Instruction
3465 *
3466 * The destination vector register group cannot overlap the
3467 * source vector register group or the source mask register.
3468 */
3469static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3470{
3471    return require_rvv(s) &&
3472           vext_check_isa_ill(s) &&
3473           require_align(a->rd, s->lmul) &&
3474           require_align(a->rs2, s->lmul) &&
3475           (a->rd != a->rs2) &&
3476           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) &&
3477           (s->vstart == 0);
3478}
3479
3480static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3481{
3482    if (vcompress_vm_check(s, a)) {
3483        uint32_t data = 0;
3484        static gen_helper_gvec_4_ptr * const fns[4] = {
3485            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3486            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3487        };
3488        TCGLabel *over = gen_new_label();
3489        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3490
3491        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3492        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3493                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3494                           cpu_env, s->vlen / 8, s->vlen / 8, data,
3495                           fns[s->sew]);
3496        mark_vs_dirty(s);
3497        gen_set_label(over);
3498        return true;
3499    }
3500    return false;
3501}
3502
3503/*
3504 * Whole Vector Register Move Instructions ignore vtype and vl setting.
3505 * Thus, we don't need to check vill bit. (Section 16.6)
3506 */
3507#define GEN_VMV_WHOLE_TRANS(NAME, LEN, SEQ)                             \
3508static bool trans_##NAME(DisasContext *s, arg_##NAME * a)               \
3509{                                                                       \
3510    if (require_rvv(s) &&                                               \
3511        QEMU_IS_ALIGNED(a->rd, LEN) &&                                  \
3512        QEMU_IS_ALIGNED(a->rs2, LEN)) {                                 \
3513        uint32_t maxsz = (s->vlen >> 3) * LEN;                          \
3514        if (s->vstart == 0) {                                           \
3515            /* EEW = 8 */                                               \
3516            tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd),                  \
3517                             vreg_ofs(s, a->rs2), maxsz, maxsz);        \
3518            mark_vs_dirty(s);                                           \
3519        } else {                                                        \
3520            TCGLabel *over = gen_new_label();                           \
3521            tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over);  \
3522                                                                        \
3523            static gen_helper_gvec_2_ptr * const fns[4] = {             \
3524                gen_helper_vmv1r_v, gen_helper_vmv2r_v,                 \
3525                gen_helper_vmv4r_v, gen_helper_vmv8r_v,                 \
3526            };                                                          \
3527            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \
3528                               cpu_env, maxsz, maxsz, 0, fns[SEQ]);     \
3529            mark_vs_dirty(s);                                           \
3530            gen_set_label(over);                                        \
3531        }                                                               \
3532        return true;                                                    \
3533    }                                                                   \
3534    return false;                                                       \
3535}
3536
3537GEN_VMV_WHOLE_TRANS(vmv1r_v, 1, 0)
3538GEN_VMV_WHOLE_TRANS(vmv2r_v, 2, 1)
3539GEN_VMV_WHOLE_TRANS(vmv4r_v, 4, 2)
3540GEN_VMV_WHOLE_TRANS(vmv8r_v, 8, 3)
3541
3542static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div)
3543{
3544    uint8_t from = (s->sew + 3) - div;
3545    bool ret = require_rvv(s) &&
3546        (from >= 3 && from <= 8) &&
3547        (a->rd != a->rs2) &&
3548        require_align(a->rd, s->lmul) &&
3549        require_align(a->rs2, s->lmul - div) &&
3550        require_vm(a->vm, a->rd) &&
3551        require_noover(a->rd, s->lmul, a->rs2, s->lmul - div);
3552    return ret;
3553}
3554
3555static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
3556{
3557    uint32_t data = 0;
3558    gen_helper_gvec_3_ptr *fn;
3559    TCGLabel *over = gen_new_label();
3560    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3561
3562    static gen_helper_gvec_3_ptr * const fns[6][4] = {
3563        {
3564            NULL, gen_helper_vzext_vf2_h,
3565            gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d
3566        },
3567        {
3568            NULL, NULL,
3569            gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d,
3570        },
3571        {
3572            NULL, NULL,
3573            NULL, gen_helper_vzext_vf8_d
3574        },
3575        {
3576            NULL, gen_helper_vsext_vf2_h,
3577            gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d
3578        },
3579        {
3580            NULL, NULL,
3581            gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d,
3582        },
3583        {
3584            NULL, NULL,
3585            NULL, gen_helper_vsext_vf8_d
3586        }
3587    };
3588
3589    fn = fns[seq][s->sew];
3590    if (fn == NULL) {
3591        return false;
3592    }
3593
3594    data = FIELD_DP32(data, VDATA, VM, a->vm);
3595
3596    tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3597                       vreg_ofs(s, a->rs2), cpu_env,
3598                       s->vlen / 8, s->vlen / 8, data, fn);
3599
3600    mark_vs_dirty(s);
3601    gen_set_label(over);
3602    return true;
3603}
3604
3605/* Vector Integer Extension */
3606#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ)             \
3607static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
3608{                                                     \
3609    if (int_ext_check(s, a, DIV)) {                   \
3610        return int_ext_op(s, a, SEQ);                 \
3611    }                                                 \
3612    return false;                                     \
3613}
3614
3615GEN_INT_EXT_TRANS(vzext_vf2, 1, 0)
3616GEN_INT_EXT_TRANS(vzext_vf4, 2, 1)
3617GEN_INT_EXT_TRANS(vzext_vf8, 3, 2)
3618GEN_INT_EXT_TRANS(vsext_vf2, 1, 3)
3619GEN_INT_EXT_TRANS(vsext_vf4, 2, 4)
3620GEN_INT_EXT_TRANS(vsext_vf8, 3, 5)
3621