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