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 && !(s->vta && s->lmul < 0)) {
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        data = FIELD_DP32(data, VDATA, VTA, s->vta);
1244        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1245                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
1246                           cpu_env, s->cfg_ptr->vlen / 8,
1247                           s->cfg_ptr->vlen / 8, data, fn);
1248    }
1249    mark_vs_dirty(s);
1250    gen_set_label(over);
1251    return true;
1252}
1253
1254/* OPIVV with GVEC IR */
1255#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
1256static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1257{                                                                  \
1258    static gen_helper_gvec_4_ptr * const fns[4] = {                \
1259        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1260        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1261    };                                                             \
1262    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1263}
1264
1265GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
1266GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
1267
1268typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
1269                              TCGv_env, TCGv_i32);
1270
1271static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
1272                        gen_helper_opivx *fn, DisasContext *s)
1273{
1274    TCGv_ptr dest, src2, mask;
1275    TCGv src1;
1276    TCGv_i32 desc;
1277    uint32_t data = 0;
1278
1279    TCGLabel *over = gen_new_label();
1280    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1281    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
1282
1283    dest = tcg_temp_new_ptr();
1284    mask = tcg_temp_new_ptr();
1285    src2 = tcg_temp_new_ptr();
1286    src1 = get_gpr(s, rs1, EXT_SIGN);
1287
1288    data = FIELD_DP32(data, VDATA, VM, vm);
1289    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1290    desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
1291                                      s->cfg_ptr->vlen / 8, data));
1292
1293    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1294    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1295    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1296
1297    fn(dest, mask, src1, src2, cpu_env, desc);
1298
1299    tcg_temp_free_ptr(dest);
1300    tcg_temp_free_ptr(mask);
1301    tcg_temp_free_ptr(src2);
1302    mark_vs_dirty(s);
1303    gen_set_label(over);
1304    return true;
1305}
1306
1307static bool opivx_check(DisasContext *s, arg_rmrr *a)
1308{
1309    return require_rvv(s) &&
1310           vext_check_isa_ill(s) &&
1311           vext_check_ss(s, a->rd, a->rs2, a->vm);
1312}
1313
1314typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
1315                         uint32_t, uint32_t);
1316
1317static inline bool
1318do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
1319              gen_helper_opivx *fn)
1320{
1321    if (!opivx_check(s, a)) {
1322        return false;
1323    }
1324
1325    if (a->vm && s->vl_eq_vlmax) {
1326        TCGv_i64 src1 = tcg_temp_new_i64();
1327
1328        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
1329        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1330                src1, MAXSZ(s), MAXSZ(s));
1331
1332        tcg_temp_free_i64(src1);
1333        mark_vs_dirty(s);
1334        return true;
1335    }
1336    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1337}
1338
1339/* OPIVX with GVEC IR */
1340#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
1341static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1342{                                                                  \
1343    static gen_helper_opivx * const fns[4] = {                     \
1344        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1345        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1346    };                                                             \
1347    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1348}
1349
1350GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
1351GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
1352
1353static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1354{
1355    tcg_gen_vec_sub8_i64(d, b, a);
1356}
1357
1358static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1359{
1360    tcg_gen_vec_sub16_i64(d, b, a);
1361}
1362
1363static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1364{
1365    tcg_gen_sub_i32(ret, arg2, arg1);
1366}
1367
1368static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1369{
1370    tcg_gen_sub_i64(ret, arg2, arg1);
1371}
1372
1373static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
1374{
1375    tcg_gen_sub_vec(vece, r, b, a);
1376}
1377
1378static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
1379                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
1380{
1381    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
1382    static const GVecGen2s rsub_op[4] = {
1383        { .fni8 = gen_vec_rsub8_i64,
1384          .fniv = gen_rsub_vec,
1385          .fno = gen_helper_vec_rsubs8,
1386          .opt_opc = vecop_list,
1387          .vece = MO_8 },
1388        { .fni8 = gen_vec_rsub16_i64,
1389          .fniv = gen_rsub_vec,
1390          .fno = gen_helper_vec_rsubs16,
1391          .opt_opc = vecop_list,
1392          .vece = MO_16 },
1393        { .fni4 = gen_rsub_i32,
1394          .fniv = gen_rsub_vec,
1395          .fno = gen_helper_vec_rsubs32,
1396          .opt_opc = vecop_list,
1397          .vece = MO_32 },
1398        { .fni8 = gen_rsub_i64,
1399          .fniv = gen_rsub_vec,
1400          .fno = gen_helper_vec_rsubs64,
1401          .opt_opc = vecop_list,
1402          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
1403          .vece = MO_64 },
1404    };
1405
1406    tcg_debug_assert(vece <= MO_64);
1407    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
1408}
1409
1410GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1411
1412typedef enum {
1413    IMM_ZX,         /* Zero-extended */
1414    IMM_SX,         /* Sign-extended */
1415    IMM_TRUNC_SEW,  /* Truncate to log(SEW) bits */
1416    IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */
1417} imm_mode_t;
1418
1419static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode)
1420{
1421    switch (imm_mode) {
1422    case IMM_ZX:
1423        return extract64(imm, 0, 5);
1424    case IMM_SX:
1425        return sextract64(imm, 0, 5);
1426    case IMM_TRUNC_SEW:
1427        return extract64(imm, 0, s->sew + 3);
1428    case IMM_TRUNC_2SEW:
1429        return extract64(imm, 0, s->sew + 4);
1430    default:
1431        g_assert_not_reached();
1432    }
1433}
1434
1435static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1436                        gen_helper_opivx *fn, DisasContext *s,
1437                        imm_mode_t imm_mode)
1438{
1439    TCGv_ptr dest, src2, mask;
1440    TCGv src1;
1441    TCGv_i32 desc;
1442    uint32_t data = 0;
1443
1444    TCGLabel *over = gen_new_label();
1445    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1446    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
1447
1448    dest = tcg_temp_new_ptr();
1449    mask = tcg_temp_new_ptr();
1450    src2 = tcg_temp_new_ptr();
1451    src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode));
1452
1453    data = FIELD_DP32(data, VDATA, VM, vm);
1454    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1455    desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
1456                                      s->cfg_ptr->vlen / 8, data));
1457
1458    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1459    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1460    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1461
1462    fn(dest, mask, src1, src2, cpu_env, desc);
1463
1464    tcg_temp_free_ptr(dest);
1465    tcg_temp_free_ptr(mask);
1466    tcg_temp_free_ptr(src2);
1467    mark_vs_dirty(s);
1468    gen_set_label(over);
1469    return true;
1470}
1471
1472typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1473                         uint32_t, uint32_t);
1474
1475static inline bool
1476do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1477              gen_helper_opivx *fn, imm_mode_t imm_mode)
1478{
1479    if (!opivx_check(s, a)) {
1480        return false;
1481    }
1482
1483    if (a->vm && s->vl_eq_vlmax) {
1484        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1485                extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
1486        mark_vs_dirty(s);
1487        return true;
1488    }
1489    return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode);
1490}
1491
1492/* OPIVI with GVEC IR */
1493#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \
1494static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1495{                                                                  \
1496    static gen_helper_opivx * const fns[4] = {                     \
1497        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1498        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1499    };                                                             \
1500    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1501                         fns[s->sew], IMM_MODE);                   \
1502}
1503
1504GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi)
1505
1506static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1507                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1508{
1509    TCGv_i64 tmp = tcg_constant_i64(c);
1510    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1511}
1512
1513GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi)
1514
1515/* Vector Widening Integer Add/Subtract */
1516
1517/* OPIVV with WIDEN */
1518static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1519{
1520    return require_rvv(s) &&
1521           vext_check_isa_ill(s) &&
1522           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
1523}
1524
1525static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1526                           gen_helper_gvec_4_ptr *fn,
1527                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1528{
1529    if (checkfn(s, a)) {
1530        uint32_t data = 0;
1531        TCGLabel *over = gen_new_label();
1532        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1533        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
1534
1535        data = FIELD_DP32(data, VDATA, VM, a->vm);
1536        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1537        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1538                           vreg_ofs(s, a->rs1),
1539                           vreg_ofs(s, a->rs2),
1540                           cpu_env, s->cfg_ptr->vlen / 8,
1541                           s->cfg_ptr->vlen / 8,
1542                           data, fn);
1543        mark_vs_dirty(s);
1544        gen_set_label(over);
1545        return true;
1546    }
1547    return false;
1548}
1549
1550#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1551static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1552{                                                            \
1553    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1554        gen_helper_##NAME##_b,                               \
1555        gen_helper_##NAME##_h,                               \
1556        gen_helper_##NAME##_w                                \
1557    };                                                       \
1558    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1559}
1560
1561GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1562GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1563GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1564GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1565
1566/* OPIVX with WIDEN */
1567static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1568{
1569    return require_rvv(s) &&
1570           vext_check_isa_ill(s) &&
1571           vext_check_ds(s, a->rd, a->rs2, a->vm);
1572}
1573
1574static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1575                           gen_helper_opivx *fn)
1576{
1577    if (opivx_widen_check(s, a)) {
1578        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1579    }
1580    return false;
1581}
1582
1583#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1584static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1585{                                                            \
1586    static gen_helper_opivx * const fns[3] = {               \
1587        gen_helper_##NAME##_b,                               \
1588        gen_helper_##NAME##_h,                               \
1589        gen_helper_##NAME##_w                                \
1590    };                                                       \
1591    return do_opivx_widen(s, a, fns[s->sew]);                \
1592}
1593
1594GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1595GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1596GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1597GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1598
1599/* WIDEN OPIVV with WIDEN */
1600static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1601{
1602    return require_rvv(s) &&
1603           vext_check_isa_ill(s) &&
1604           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
1605}
1606
1607static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1608                           gen_helper_gvec_4_ptr *fn)
1609{
1610    if (opiwv_widen_check(s, a)) {
1611        uint32_t data = 0;
1612        TCGLabel *over = gen_new_label();
1613        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1614        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
1615
1616        data = FIELD_DP32(data, VDATA, VM, a->vm);
1617        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1618        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1619                           vreg_ofs(s, a->rs1),
1620                           vreg_ofs(s, a->rs2),
1621                           cpu_env, s->cfg_ptr->vlen / 8,
1622                           s->cfg_ptr->vlen / 8, data, fn);
1623        mark_vs_dirty(s);
1624        gen_set_label(over);
1625        return true;
1626    }
1627    return false;
1628}
1629
1630#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1631static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1632{                                                            \
1633    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1634        gen_helper_##NAME##_b,                               \
1635        gen_helper_##NAME##_h,                               \
1636        gen_helper_##NAME##_w                                \
1637    };                                                       \
1638    return do_opiwv_widen(s, a, fns[s->sew]);                \
1639}
1640
1641GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1642GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1643GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1644GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1645
1646/* WIDEN OPIVX with WIDEN */
1647static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1648{
1649    return require_rvv(s) &&
1650           vext_check_isa_ill(s) &&
1651           vext_check_dd(s, a->rd, a->rs2, a->vm);
1652}
1653
1654static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1655                           gen_helper_opivx *fn)
1656{
1657    if (opiwx_widen_check(s, a)) {
1658        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1659    }
1660    return false;
1661}
1662
1663#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1664static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1665{                                                            \
1666    static gen_helper_opivx * const fns[3] = {               \
1667        gen_helper_##NAME##_b,                               \
1668        gen_helper_##NAME##_h,                               \
1669        gen_helper_##NAME##_w                                \
1670    };                                                       \
1671    return do_opiwx_widen(s, a, fns[s->sew]);                \
1672}
1673
1674GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1675GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1676GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1677GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1678
1679/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1680/* OPIVV without GVEC IR */
1681#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1682static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1683{                                                                  \
1684    if (CHECK(s, a)) {                                             \
1685        uint32_t data = 0;                                         \
1686        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1687            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1688            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1689        };                                                         \
1690        TCGLabel *over = gen_new_label();                          \
1691        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1692        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
1693                                                                   \
1694        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1695        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1696        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1697                           vreg_ofs(s, a->rs1),                    \
1698                           vreg_ofs(s, a->rs2), cpu_env,           \
1699                           s->cfg_ptr->vlen / 8,                   \
1700                           s->cfg_ptr->vlen / 8, data,             \
1701                           fns[s->sew]);                           \
1702        mark_vs_dirty(s);                                          \
1703        gen_set_label(over);                                       \
1704        return true;                                               \
1705    }                                                              \
1706    return false;                                                  \
1707}
1708
1709/*
1710 * For vadc and vsbc, an illegal instruction exception is raised if the
1711 * destination vector register is v0 and LMUL > 1. (Section 11.4)
1712 */
1713static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1714{
1715    return require_rvv(s) &&
1716           vext_check_isa_ill(s) &&
1717           (a->rd != 0) &&
1718           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1719}
1720
1721GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1722GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1723
1724/*
1725 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1726 * destination vector register overlaps a source vector register group.
1727 */
1728static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1729{
1730    return require_rvv(s) &&
1731           vext_check_isa_ill(s) &&
1732           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1733}
1734
1735GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1736GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1737
1738static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1739{
1740    return require_rvv(s) &&
1741           vext_check_isa_ill(s) &&
1742           (a->rd != 0) &&
1743           vext_check_ss(s, a->rd, a->rs2, a->vm);
1744}
1745
1746/* OPIVX without GVEC IR */
1747#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1748static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1749{                                                                        \
1750    if (CHECK(s, a)) {                                                   \
1751        static gen_helper_opivx * const fns[4] = {                       \
1752            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1753            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1754        };                                                               \
1755                                                                         \
1756        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1757    }                                                                    \
1758    return false;                                                        \
1759}
1760
1761GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1762GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1763
1764static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1765{
1766    return require_rvv(s) &&
1767           vext_check_isa_ill(s) &&
1768           vext_check_ms(s, a->rd, a->rs2);
1769}
1770
1771GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1772GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1773
1774/* OPIVI without GVEC IR */
1775#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK)                    \
1776static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1777{                                                                        \
1778    if (CHECK(s, a)) {                                                   \
1779        static gen_helper_opivx * const fns[4] = {                       \
1780            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1781            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1782        };                                                               \
1783        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1784                           fns[s->sew], s, IMM_MODE);                    \
1785    }                                                                    \
1786    return false;                                                        \
1787}
1788
1789GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check)
1790GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check)
1791
1792/* Vector Bitwise Logical Instructions */
1793GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1794GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1795GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1796GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1797GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1798GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1799GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi)
1800GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx,  ori)
1801GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori)
1802
1803/* Vector Single-Width Bit Shift Instructions */
1804GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1805GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1806GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1807
1808typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1809                           uint32_t, uint32_t);
1810
1811static inline bool
1812do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1813                    gen_helper_opivx *fn)
1814{
1815    if (!opivx_check(s, a)) {
1816        return false;
1817    }
1818
1819    if (a->vm && s->vl_eq_vlmax) {
1820        TCGv_i32 src1 = tcg_temp_new_i32();
1821
1822        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1823        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1824        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1825                src1, MAXSZ(s), MAXSZ(s));
1826
1827        tcg_temp_free_i32(src1);
1828        mark_vs_dirty(s);
1829        return true;
1830    }
1831    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1832}
1833
1834#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1835static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1836{                                                                         \
1837    static gen_helper_opivx * const fns[4] = {                            \
1838        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1839        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1840    };                                                                    \
1841                                                                          \
1842    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1843}
1844
1845GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1846GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1847GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1848
1849GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_TRUNC_SEW, vsll_vx, shli)
1850GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_TRUNC_SEW, vsrl_vx, shri)
1851GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_TRUNC_SEW, vsra_vx, sari)
1852
1853/* Vector Narrowing Integer Right Shift Instructions */
1854static bool opiwv_narrow_check(DisasContext *s, arg_rmrr *a)
1855{
1856    return require_rvv(s) &&
1857           vext_check_isa_ill(s) &&
1858           vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm);
1859}
1860
1861/* OPIVV with NARROW */
1862#define GEN_OPIWV_NARROW_TRANS(NAME)                               \
1863static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1864{                                                                  \
1865    if (opiwv_narrow_check(s, a)) {                                \
1866        uint32_t data = 0;                                         \
1867        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1868            gen_helper_##NAME##_b,                                 \
1869            gen_helper_##NAME##_h,                                 \
1870            gen_helper_##NAME##_w,                                 \
1871        };                                                         \
1872        TCGLabel *over = gen_new_label();                          \
1873        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1874        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
1875                                                                   \
1876        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1877        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1878        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1879                           vreg_ofs(s, a->rs1),                    \
1880                           vreg_ofs(s, a->rs2), cpu_env,           \
1881                           s->cfg_ptr->vlen / 8,                   \
1882                           s->cfg_ptr->vlen / 8, data,             \
1883                           fns[s->sew]);                           \
1884        mark_vs_dirty(s);                                          \
1885        gen_set_label(over);                                       \
1886        return true;                                               \
1887    }                                                              \
1888    return false;                                                  \
1889}
1890GEN_OPIWV_NARROW_TRANS(vnsra_wv)
1891GEN_OPIWV_NARROW_TRANS(vnsrl_wv)
1892
1893static bool opiwx_narrow_check(DisasContext *s, arg_rmrr *a)
1894{
1895    return require_rvv(s) &&
1896           vext_check_isa_ill(s) &&
1897           vext_check_sd(s, a->rd, a->rs2, a->vm);
1898}
1899
1900/* OPIVX with NARROW */
1901#define GEN_OPIWX_NARROW_TRANS(NAME)                                     \
1902static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1903{                                                                        \
1904    if (opiwx_narrow_check(s, a)) {                                      \
1905        static gen_helper_opivx * const fns[3] = {                       \
1906            gen_helper_##NAME##_b,                                       \
1907            gen_helper_##NAME##_h,                                       \
1908            gen_helper_##NAME##_w,                                       \
1909        };                                                               \
1910        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1911    }                                                                    \
1912    return false;                                                        \
1913}
1914
1915GEN_OPIWX_NARROW_TRANS(vnsra_wx)
1916GEN_OPIWX_NARROW_TRANS(vnsrl_wx)
1917
1918/* OPIWI with NARROW */
1919#define GEN_OPIWI_NARROW_TRANS(NAME, IMM_MODE, OPIVX)                    \
1920static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1921{                                                                        \
1922    if (opiwx_narrow_check(s, a)) {                                      \
1923        static gen_helper_opivx * const fns[3] = {                       \
1924            gen_helper_##OPIVX##_b,                                      \
1925            gen_helper_##OPIVX##_h,                                      \
1926            gen_helper_##OPIVX##_w,                                      \
1927        };                                                               \
1928        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1929                           fns[s->sew], s, IMM_MODE);                    \
1930    }                                                                    \
1931    return false;                                                        \
1932}
1933
1934GEN_OPIWI_NARROW_TRANS(vnsra_wi, IMM_ZX, vnsra_wx)
1935GEN_OPIWI_NARROW_TRANS(vnsrl_wi, IMM_ZX, vnsrl_wx)
1936
1937/* Vector Integer Comparison Instructions */
1938/*
1939 * For all comparison instructions, an illegal instruction exception is raised
1940 * if the destination vector register overlaps a source vector register group
1941 * and LMUL > 1.
1942 */
1943static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1944{
1945    return require_rvv(s) &&
1946           vext_check_isa_ill(s) &&
1947           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1948}
1949
1950GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1951GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1952GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1953GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1954GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1955GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1956
1957static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1958{
1959    return require_rvv(s) &&
1960           vext_check_isa_ill(s) &&
1961           vext_check_ms(s, a->rd, a->rs2);
1962}
1963
1964GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1965GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1966GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1967GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1968GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1969GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1970GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1971GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1972
1973GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check)
1974GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check)
1975GEN_OPIVI_TRANS(vmsleu_vi, IMM_SX, vmsleu_vx, opivx_cmp_check)
1976GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check)
1977GEN_OPIVI_TRANS(vmsgtu_vi, IMM_SX, vmsgtu_vx, opivx_cmp_check)
1978GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check)
1979
1980/* Vector Integer Min/Max Instructions */
1981GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1982GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1983GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1984GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1985GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1986GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1987GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1988GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1989
1990/* Vector Single-Width Integer Multiply Instructions */
1991
1992static bool vmulh_vv_check(DisasContext *s, arg_rmrr *a)
1993{
1994    /*
1995     * All Zve* extensions support all vector integer instructions,
1996     * except that the vmulh integer multiply variants
1997     * that return the high word of the product
1998     * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx)
1999     * are not included for EEW=64 in Zve64*. (Section 18.2)
2000     */
2001    return opivv_check(s, a) &&
2002           (!has_ext(s, RVV) &&
2003            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2004}
2005
2006static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a)
2007{
2008    /*
2009     * All Zve* extensions support all vector integer instructions,
2010     * except that the vmulh integer multiply variants
2011     * that return the high word of the product
2012     * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx)
2013     * are not included for EEW=64 in Zve64*. (Section 18.2)
2014     */
2015    return opivx_check(s, a) &&
2016           (!has_ext(s, RVV) &&
2017            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2018}
2019
2020GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
2021GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check)
2022GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check)
2023GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check)
2024GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
2025GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check)
2026GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check)
2027GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check)
2028
2029/* Vector Integer Divide Instructions */
2030GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
2031GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
2032GEN_OPIVV_TRANS(vremu_vv, opivv_check)
2033GEN_OPIVV_TRANS(vrem_vv, opivv_check)
2034GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
2035GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
2036GEN_OPIVX_TRANS(vremu_vx, opivx_check)
2037GEN_OPIVX_TRANS(vrem_vx, opivx_check)
2038
2039/* Vector Widening Integer Multiply Instructions */
2040GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
2041GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
2042GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
2043GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
2044GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
2045GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
2046
2047/* Vector Single-Width Integer Multiply-Add Instructions */
2048GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
2049GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
2050GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
2051GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
2052GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
2053GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
2054GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
2055GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
2056
2057/* Vector Widening Integer Multiply-Add Instructions */
2058GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
2059GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
2060GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
2061GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
2062GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
2063GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
2064GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
2065
2066/* Vector Integer Merge and Move Instructions */
2067static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
2068{
2069    if (require_rvv(s) &&
2070        vext_check_isa_ill(s) &&
2071        /* vmv.v.v has rs2 = 0 and vm = 1 */
2072        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
2073        if (s->vl_eq_vlmax) {
2074            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
2075                             vreg_ofs(s, a->rs1),
2076                             MAXSZ(s), MAXSZ(s));
2077        } else {
2078            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2079            static gen_helper_gvec_2_ptr * const fns[4] = {
2080                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
2081                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
2082            };
2083            TCGLabel *over = gen_new_label();
2084            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2085            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2086
2087            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
2088                               cpu_env, s->cfg_ptr->vlen / 8,
2089                               s->cfg_ptr->vlen / 8, data,
2090                               fns[s->sew]);
2091            gen_set_label(over);
2092        }
2093        mark_vs_dirty(s);
2094        return true;
2095    }
2096    return false;
2097}
2098
2099typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
2100static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
2101{
2102    if (require_rvv(s) &&
2103        vext_check_isa_ill(s) &&
2104        /* vmv.v.x has rs2 = 0 and vm = 1 */
2105        vext_check_ss(s, a->rd, 0, 1)) {
2106        TCGv s1;
2107        TCGLabel *over = gen_new_label();
2108        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2109        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2110
2111        s1 = get_gpr(s, a->rs1, EXT_SIGN);
2112
2113        if (s->vl_eq_vlmax) {
2114            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
2115                                MAXSZ(s), MAXSZ(s), s1);
2116        } else {
2117            TCGv_i32 desc;
2118            TCGv_i64 s1_i64 = tcg_temp_new_i64();
2119            TCGv_ptr dest = tcg_temp_new_ptr();
2120            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2121            static gen_helper_vmv_vx * const fns[4] = {
2122                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2123                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2124            };
2125
2126            tcg_gen_ext_tl_i64(s1_i64, s1);
2127            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2128                                              s->cfg_ptr->vlen / 8, data));
2129            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2130            fns[s->sew](dest, s1_i64, cpu_env, desc);
2131
2132            tcg_temp_free_ptr(dest);
2133            tcg_temp_free_i64(s1_i64);
2134        }
2135
2136        mark_vs_dirty(s);
2137        gen_set_label(over);
2138        return true;
2139    }
2140    return false;
2141}
2142
2143static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
2144{
2145    if (require_rvv(s) &&
2146        vext_check_isa_ill(s) &&
2147        /* vmv.v.i has rs2 = 0 and vm = 1 */
2148        vext_check_ss(s, a->rd, 0, 1)) {
2149        int64_t simm = sextract64(a->rs1, 0, 5);
2150        if (s->vl_eq_vlmax) {
2151            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
2152                                 MAXSZ(s), MAXSZ(s), simm);
2153            mark_vs_dirty(s);
2154        } else {
2155            TCGv_i32 desc;
2156            TCGv_i64 s1;
2157            TCGv_ptr dest;
2158            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2159            static gen_helper_vmv_vx * const fns[4] = {
2160                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2161                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2162            };
2163            TCGLabel *over = gen_new_label();
2164            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2165            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2166
2167            s1 = tcg_constant_i64(simm);
2168            dest = tcg_temp_new_ptr();
2169            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2170                                              s->cfg_ptr->vlen / 8, data));
2171            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2172            fns[s->sew](dest, s1, cpu_env, desc);
2173
2174            tcg_temp_free_ptr(dest);
2175            mark_vs_dirty(s);
2176            gen_set_label(over);
2177        }
2178        return true;
2179    }
2180    return false;
2181}
2182
2183GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
2184GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
2185GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
2186
2187/*
2188 *** Vector Fixed-Point Arithmetic Instructions
2189 */
2190
2191/* Vector Single-Width Saturating Add and Subtract */
2192GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
2193GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
2194GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
2195GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
2196GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
2197GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
2198GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
2199GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
2200GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check)
2201GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
2202
2203/* Vector Single-Width Averaging Add and Subtract */
2204GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
2205GEN_OPIVV_TRANS(vaaddu_vv, opivv_check)
2206GEN_OPIVV_TRANS(vasub_vv, opivv_check)
2207GEN_OPIVV_TRANS(vasubu_vv, opivv_check)
2208GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
2209GEN_OPIVX_TRANS(vaaddu_vx,  opivx_check)
2210GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
2211GEN_OPIVX_TRANS(vasubu_vx,  opivx_check)
2212
2213/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
2214
2215static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a)
2216{
2217    /*
2218     * All Zve* extensions support all vector fixed-point arithmetic
2219     * instructions, except that vsmul.vv and vsmul.vx are not supported
2220     * for EEW=64 in Zve64*. (Section 18.2)
2221     */
2222    return opivv_check(s, a) &&
2223           (!has_ext(s, RVV) &&
2224            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2225}
2226
2227static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a)
2228{
2229    /*
2230     * All Zve* extensions support all vector fixed-point arithmetic
2231     * instructions, except that vsmul.vv and vsmul.vx are not supported
2232     * for EEW=64 in Zve64*. (Section 18.2)
2233     */
2234    return opivx_check(s, a) &&
2235           (!has_ext(s, RVV) &&
2236            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2237}
2238
2239GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check)
2240GEN_OPIVX_TRANS(vsmul_vx,  vsmul_vx_check)
2241
2242/* Vector Single-Width Scaling Shift Instructions */
2243GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
2244GEN_OPIVV_TRANS(vssra_vv, opivv_check)
2245GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
2246GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
2247GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check)
2248GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check)
2249
2250/* Vector Narrowing Fixed-Point Clip Instructions */
2251GEN_OPIWV_NARROW_TRANS(vnclipu_wv)
2252GEN_OPIWV_NARROW_TRANS(vnclip_wv)
2253GEN_OPIWX_NARROW_TRANS(vnclipu_wx)
2254GEN_OPIWX_NARROW_TRANS(vnclip_wx)
2255GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx)
2256GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx)
2257
2258/*
2259 *** Vector Float Point Arithmetic Instructions
2260 */
2261
2262/*
2263 * As RVF-only cpus always have values NaN-boxed to 64-bits,
2264 * RVF and RVD can be treated equally.
2265 * We don't have to deal with the cases of: SEW > FLEN.
2266 *
2267 * If SEW < FLEN, check whether input fp register is a valid
2268 * NaN-boxed value, in which case the least-significant SEW bits
2269 * of the f regsiter are used, else the canonical NaN value is used.
2270 */
2271static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
2272{
2273    switch (s->sew) {
2274    case 1:
2275        gen_check_nanbox_h(out, in);
2276        break;
2277    case 2:
2278        gen_check_nanbox_s(out, in);
2279        break;
2280    case 3:
2281        tcg_gen_mov_i64(out, in);
2282        break;
2283    default:
2284        g_assert_not_reached();
2285    }
2286}
2287
2288/* Vector Single-Width Floating-Point Add/Subtract Instructions */
2289
2290/*
2291 * If the current SEW does not correspond to a supported IEEE floating-point
2292 * type, an illegal instruction exception is raised.
2293 */
2294static bool opfvv_check(DisasContext *s, arg_rmrr *a)
2295{
2296    return require_rvv(s) &&
2297           require_rvf(s) &&
2298           vext_check_isa_ill(s) &&
2299           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm) &&
2300           require_zve32f(s) &&
2301           require_zve64f(s);
2302}
2303
2304/* OPFVV without GVEC IR */
2305#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2306static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2307{                                                                  \
2308    if (CHECK(s, a)) {                                             \
2309        uint32_t data = 0;                                         \
2310        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2311            gen_helper_##NAME##_h,                                 \
2312            gen_helper_##NAME##_w,                                 \
2313            gen_helper_##NAME##_d,                                 \
2314        };                                                         \
2315        TCGLabel *over = gen_new_label();                          \
2316        gen_set_rm(s, RISCV_FRM_DYN);                              \
2317        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2318        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2319                                                                   \
2320        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2321        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2322        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2323                           vreg_ofs(s, a->rs1),                    \
2324                           vreg_ofs(s, a->rs2), cpu_env,           \
2325                           s->cfg_ptr->vlen / 8,                   \
2326                           s->cfg_ptr->vlen / 8, data,             \
2327                           fns[s->sew - 1]);                       \
2328        mark_vs_dirty(s);                                          \
2329        gen_set_label(over);                                       \
2330        return true;                                               \
2331    }                                                              \
2332    return false;                                                  \
2333}
2334GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2335GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2336
2337typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2338                              TCGv_env, TCGv_i32);
2339
2340static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2341                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2342{
2343    TCGv_ptr dest, src2, mask;
2344    TCGv_i32 desc;
2345    TCGv_i64 t1;
2346
2347    TCGLabel *over = gen_new_label();
2348    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2349    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2350
2351    dest = tcg_temp_new_ptr();
2352    mask = tcg_temp_new_ptr();
2353    src2 = tcg_temp_new_ptr();
2354    desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2355                                      s->cfg_ptr->vlen / 8, data));
2356
2357    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2358    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2359    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2360
2361    /* NaN-box f[rs1] */
2362    t1 = tcg_temp_new_i64();
2363    do_nanbox(s, t1, cpu_fpr[rs1]);
2364
2365    fn(dest, mask, t1, src2, cpu_env, desc);
2366
2367    tcg_temp_free_ptr(dest);
2368    tcg_temp_free_ptr(mask);
2369    tcg_temp_free_ptr(src2);
2370    tcg_temp_free_i64(t1);
2371    mark_vs_dirty(s);
2372    gen_set_label(over);
2373    return true;
2374}
2375
2376/*
2377 * If the current SEW does not correspond to a supported IEEE floating-point
2378 * type, an illegal instruction exception is raised
2379 */
2380static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2381{
2382    return require_rvv(s) &&
2383           require_rvf(s) &&
2384           vext_check_isa_ill(s) &&
2385           vext_check_ss(s, a->rd, a->rs2, a->vm) &&
2386           require_zve32f(s) &&
2387           require_zve64f(s);
2388}
2389
2390/* OPFVF without GVEC IR */
2391#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2392static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2393{                                                                 \
2394    if (CHECK(s, a)) {                                            \
2395        uint32_t data = 0;                                        \
2396        static gen_helper_opfvf *const fns[3] = {                 \
2397            gen_helper_##NAME##_h,                                \
2398            gen_helper_##NAME##_w,                                \
2399            gen_helper_##NAME##_d,                                \
2400        };                                                        \
2401        gen_set_rm(s, RISCV_FRM_DYN);                             \
2402        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2403        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2404        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2405                           fns[s->sew - 1], s);                   \
2406    }                                                             \
2407    return false;                                                 \
2408}
2409
2410GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2411GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2412GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2413
2414/* Vector Widening Floating-Point Add/Subtract Instructions */
2415static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2416{
2417    return require_rvv(s) &&
2418           require_scale_rvf(s) &&
2419           (s->sew != MO_8) &&
2420           vext_check_isa_ill(s) &&
2421           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
2422           require_scale_zve32f(s) &&
2423           require_scale_zve64f(s);
2424}
2425
2426/* OPFVV with WIDEN */
2427#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2428static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2429{                                                                \
2430    if (CHECK(s, a)) {                                           \
2431        uint32_t data = 0;                                       \
2432        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2433            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2434        };                                                       \
2435        TCGLabel *over = gen_new_label();                        \
2436        gen_set_rm(s, RISCV_FRM_DYN);                            \
2437        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2438        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\
2439                                                                 \
2440        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2441        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2442        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2443                           vreg_ofs(s, a->rs1),                  \
2444                           vreg_ofs(s, a->rs2), cpu_env,         \
2445                           s->cfg_ptr->vlen / 8,                 \
2446                           s->cfg_ptr->vlen / 8, data,           \
2447                           fns[s->sew - 1]);                     \
2448        mark_vs_dirty(s);                                        \
2449        gen_set_label(over);                                     \
2450        return true;                                             \
2451    }                                                            \
2452    return false;                                                \
2453}
2454
2455GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2456GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2457
2458static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2459{
2460    return require_rvv(s) &&
2461           require_scale_rvf(s) &&
2462           (s->sew != MO_8) &&
2463           vext_check_isa_ill(s) &&
2464           vext_check_ds(s, a->rd, a->rs2, a->vm) &&
2465           require_scale_zve32f(s) &&
2466           require_scale_zve64f(s);
2467}
2468
2469/* OPFVF with WIDEN */
2470#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2471static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2472{                                                                \
2473    if (opfvf_widen_check(s, a)) {                               \
2474        uint32_t data = 0;                                       \
2475        static gen_helper_opfvf *const fns[2] = {                \
2476            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2477        };                                                       \
2478        gen_set_rm(s, RISCV_FRM_DYN);                            \
2479        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2480        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2481        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2482                           fns[s->sew - 1], s);                  \
2483    }                                                            \
2484    return false;                                                \
2485}
2486
2487GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2488GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2489
2490static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2491{
2492    return require_rvv(s) &&
2493           require_scale_rvf(s) &&
2494           (s->sew != MO_8) &&
2495           vext_check_isa_ill(s) &&
2496           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm) &&
2497           require_scale_zve32f(s) &&
2498           require_scale_zve64f(s);
2499}
2500
2501/* WIDEN OPFVV with WIDEN */
2502#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2503static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2504{                                                                  \
2505    if (opfwv_widen_check(s, a)) {                                 \
2506        uint32_t data = 0;                                         \
2507        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2508            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2509        };                                                         \
2510        TCGLabel *over = gen_new_label();                          \
2511        gen_set_rm(s, RISCV_FRM_DYN);                              \
2512        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2513        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2514                                                                   \
2515        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2516        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2517        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2518                           vreg_ofs(s, a->rs1),                    \
2519                           vreg_ofs(s, a->rs2), cpu_env,           \
2520                           s->cfg_ptr->vlen / 8,                   \
2521                           s->cfg_ptr->vlen / 8, data,             \
2522                           fns[s->sew - 1]);                       \
2523        mark_vs_dirty(s);                                          \
2524        gen_set_label(over);                                       \
2525        return true;                                               \
2526    }                                                              \
2527    return false;                                                  \
2528}
2529
2530GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2531GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2532
2533static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2534{
2535    return require_rvv(s) &&
2536           require_scale_rvf(s) &&
2537           (s->sew != MO_8) &&
2538           vext_check_isa_ill(s) &&
2539           vext_check_dd(s, a->rd, a->rs2, a->vm) &&
2540           require_scale_zve32f(s) &&
2541           require_scale_zve64f(s);
2542}
2543
2544/* WIDEN OPFVF with WIDEN */
2545#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2546static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2547{                                                                \
2548    if (opfwf_widen_check(s, a)) {                               \
2549        uint32_t data = 0;                                       \
2550        static gen_helper_opfvf *const fns[2] = {                \
2551            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2552        };                                                       \
2553        gen_set_rm(s, RISCV_FRM_DYN);                            \
2554        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2555        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2556        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2557                           fns[s->sew - 1], s);                  \
2558    }                                                            \
2559    return false;                                                \
2560}
2561
2562GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2563GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2564
2565/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2566GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2567GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2568GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2569GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2570GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2571
2572/* Vector Widening Floating-Point Multiply */
2573GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2574GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2575
2576/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2577GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2578GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2579GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2580GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2581GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2582GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2583GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2584GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2585GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2586GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2587GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2588GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2589GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2590GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2591GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2592GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2593
2594/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2595GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2596GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2597GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2598GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2599GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2600GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2601GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2602GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2603
2604/* Vector Floating-Point Square-Root Instruction */
2605
2606/*
2607 * If the current SEW does not correspond to a supported IEEE floating-point
2608 * type, an illegal instruction exception is raised
2609 */
2610static bool opfv_check(DisasContext *s, arg_rmr *a)
2611{
2612    return require_rvv(s) &&
2613           require_rvf(s) &&
2614           vext_check_isa_ill(s) &&
2615           /* OPFV instructions ignore vs1 check */
2616           vext_check_ss(s, a->rd, a->rs2, a->vm) &&
2617           require_zve32f(s) &&
2618           require_zve64f(s);
2619}
2620
2621static bool do_opfv(DisasContext *s, arg_rmr *a,
2622                    gen_helper_gvec_3_ptr *fn,
2623                    bool (*checkfn)(DisasContext *, arg_rmr *),
2624                    int rm)
2625{
2626    if (checkfn(s, a)) {
2627        if (rm != RISCV_FRM_DYN) {
2628            gen_set_rm(s, RISCV_FRM_DYN);
2629        }
2630
2631        uint32_t data = 0;
2632        TCGLabel *over = gen_new_label();
2633        gen_set_rm(s, rm);
2634        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2635        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2636
2637        data = FIELD_DP32(data, VDATA, VM, a->vm);
2638        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2639        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2640                           vreg_ofs(s, a->rs2), cpu_env,
2641                           s->cfg_ptr->vlen / 8,
2642                           s->cfg_ptr->vlen / 8, data, fn);
2643        mark_vs_dirty(s);
2644        gen_set_label(over);
2645        return true;
2646    }
2647    return false;
2648}
2649
2650#define GEN_OPFV_TRANS(NAME, CHECK, FRM)               \
2651static bool trans_##NAME(DisasContext *s, arg_rmr *a)  \
2652{                                                      \
2653    static gen_helper_gvec_3_ptr * const fns[3] = {    \
2654        gen_helper_##NAME##_h,                         \
2655        gen_helper_##NAME##_w,                         \
2656        gen_helper_##NAME##_d                          \
2657    };                                                 \
2658    return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \
2659}
2660
2661GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN)
2662GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN)
2663GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN)
2664
2665/* Vector Floating-Point MIN/MAX Instructions */
2666GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2667GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2668GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2669GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2670
2671/* Vector Floating-Point Sign-Injection Instructions */
2672GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2673GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2674GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2675GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2676GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2677GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2678
2679/* Vector Floating-Point Compare Instructions */
2680static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2681{
2682    return require_rvv(s) &&
2683           require_rvf(s) &&
2684           vext_check_isa_ill(s) &&
2685           vext_check_mss(s, a->rd, a->rs1, a->rs2) &&
2686           require_zve32f(s) &&
2687           require_zve64f(s);
2688}
2689
2690GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2691GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2692GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2693GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2694
2695static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2696{
2697    return require_rvv(s) &&
2698           require_rvf(s) &&
2699           vext_check_isa_ill(s) &&
2700           vext_check_ms(s, a->rd, a->rs2) &&
2701           require_zve32f(s) &&
2702           require_zve64f(s);
2703}
2704
2705GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2706GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2707GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2708GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2709GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2710GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2711
2712/* Vector Floating-Point Classify Instruction */
2713GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN)
2714
2715/* Vector Floating-Point Merge Instruction */
2716GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2717
2718static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2719{
2720    if (require_rvv(s) &&
2721        require_rvf(s) &&
2722        vext_check_isa_ill(s) &&
2723        require_align(a->rd, s->lmul) &&
2724        require_zve32f(s) &&
2725        require_zve64f(s)) {
2726        gen_set_rm(s, RISCV_FRM_DYN);
2727
2728        TCGv_i64 t1;
2729
2730        if (s->vl_eq_vlmax) {
2731            t1 = tcg_temp_new_i64();
2732            /* NaN-box f[rs1] */
2733            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2734
2735            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2736                                 MAXSZ(s), MAXSZ(s), t1);
2737            mark_vs_dirty(s);
2738        } else {
2739            TCGv_ptr dest;
2740            TCGv_i32 desc;
2741            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2742            static gen_helper_vmv_vx * const fns[3] = {
2743                gen_helper_vmv_v_x_h,
2744                gen_helper_vmv_v_x_w,
2745                gen_helper_vmv_v_x_d,
2746            };
2747            TCGLabel *over = gen_new_label();
2748            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2749            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2750
2751            t1 = tcg_temp_new_i64();
2752            /* NaN-box f[rs1] */
2753            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2754
2755            dest = tcg_temp_new_ptr();
2756            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2757                                              s->cfg_ptr->vlen / 8, data));
2758            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2759
2760            fns[s->sew - 1](dest, t1, cpu_env, desc);
2761
2762            tcg_temp_free_ptr(dest);
2763            mark_vs_dirty(s);
2764            gen_set_label(over);
2765        }
2766        tcg_temp_free_i64(t1);
2767        return true;
2768    }
2769    return false;
2770}
2771
2772/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2773#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM)               \
2774static bool trans_##NAME(DisasContext *s, arg_rmr *a)       \
2775{                                                           \
2776    static gen_helper_gvec_3_ptr * const fns[3] = {         \
2777        gen_helper_##HELPER##_h,                            \
2778        gen_helper_##HELPER##_w,                            \
2779        gen_helper_##HELPER##_d                             \
2780    };                                                      \
2781    return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \
2782}
2783
2784GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN)
2785GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN)
2786GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN)
2787GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN)
2788/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */
2789GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ)
2790GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ)
2791
2792/* Widening Floating-Point/Integer Type-Convert Instructions */
2793
2794/*
2795 * If the current SEW does not correspond to a supported IEEE floating-point
2796 * type, an illegal instruction exception is raised
2797 */
2798static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2799{
2800    return require_rvv(s) &&
2801           vext_check_isa_ill(s) &&
2802           vext_check_ds(s, a->rd, a->rs2, a->vm);
2803}
2804
2805static bool opxfv_widen_check(DisasContext *s, arg_rmr *a)
2806{
2807    return opfv_widen_check(s, a) &&
2808           require_rvf(s) &&
2809           require_zve32f(s) &&
2810           require_zve64f(s);
2811}
2812
2813static bool opffv_widen_check(DisasContext *s, arg_rmr *a)
2814{
2815    return opfv_widen_check(s, a) &&
2816           require_scale_rvf(s) &&
2817           (s->sew != MO_8) &&
2818           require_scale_zve32f(s) &&
2819           require_scale_zve64f(s);
2820}
2821
2822#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM)             \
2823static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2824{                                                                  \
2825    if (CHECK(s, a)) {                                             \
2826        if (FRM != RISCV_FRM_DYN) {                                \
2827            gen_set_rm(s, RISCV_FRM_DYN);                          \
2828        }                                                          \
2829                                                                   \
2830        uint32_t data = 0;                                         \
2831        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2832            gen_helper_##HELPER##_h,                               \
2833            gen_helper_##HELPER##_w,                               \
2834        };                                                         \
2835        TCGLabel *over = gen_new_label();                          \
2836        gen_set_rm(s, FRM);                                        \
2837        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2838        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2839                                                                   \
2840        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2841        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2842        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2843                           vreg_ofs(s, a->rs2), cpu_env,           \
2844                           s->cfg_ptr->vlen / 8,                   \
2845                           s->cfg_ptr->vlen / 8, data,             \
2846                           fns[s->sew - 1]);                       \
2847        mark_vs_dirty(s);                                          \
2848        gen_set_label(over);                                       \
2849        return true;                                               \
2850    }                                                              \
2851    return false;                                                  \
2852}
2853
2854GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2855                     RISCV_FRM_DYN)
2856GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2857                     RISCV_FRM_DYN)
2858GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v,
2859                     RISCV_FRM_DYN)
2860/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */
2861GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2862                     RISCV_FRM_RTZ)
2863GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2864                     RISCV_FRM_RTZ)
2865
2866static bool opfxv_widen_check(DisasContext *s, arg_rmr *a)
2867{
2868    return require_rvv(s) &&
2869           require_scale_rvf(s) &&
2870           vext_check_isa_ill(s) &&
2871           /* OPFV widening instructions ignore vs1 check */
2872           vext_check_ds(s, a->rd, a->rs2, a->vm) &&
2873           require_scale_zve32f(s) &&
2874           require_scale_zve64f(s);
2875}
2876
2877#define GEN_OPFXV_WIDEN_TRANS(NAME)                                \
2878static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2879{                                                                  \
2880    if (opfxv_widen_check(s, a)) {                                 \
2881        uint32_t data = 0;                                         \
2882        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2883            gen_helper_##NAME##_b,                                 \
2884            gen_helper_##NAME##_h,                                 \
2885            gen_helper_##NAME##_w,                                 \
2886        };                                                         \
2887        TCGLabel *over = gen_new_label();                          \
2888        gen_set_rm(s, RISCV_FRM_DYN);                              \
2889        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2890        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2891                                                                   \
2892        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2893        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2894                           vreg_ofs(s, a->rs2), cpu_env,           \
2895                           s->cfg_ptr->vlen / 8,                   \
2896                           s->cfg_ptr->vlen / 8, data,             \
2897                           fns[s->sew]);                           \
2898        mark_vs_dirty(s);                                          \
2899        gen_set_label(over);                                       \
2900        return true;                                               \
2901    }                                                              \
2902    return false;                                                  \
2903}
2904
2905GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v)
2906GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v)
2907
2908/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2909
2910/*
2911 * If the current SEW does not correspond to a supported IEEE floating-point
2912 * type, an illegal instruction exception is raised
2913 */
2914static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2915{
2916    return require_rvv(s) &&
2917           vext_check_isa_ill(s) &&
2918           /* OPFV narrowing instructions ignore vs1 check */
2919           vext_check_sd(s, a->rd, a->rs2, a->vm);
2920}
2921
2922static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a)
2923{
2924    return opfv_narrow_check(s, a) &&
2925           require_rvf(s) &&
2926           (s->sew != MO_64) &&
2927           require_zve32f(s) &&
2928           require_zve64f(s);
2929}
2930
2931static bool opffv_narrow_check(DisasContext *s, arg_rmr *a)
2932{
2933    return opfv_narrow_check(s, a) &&
2934           require_scale_rvf(s) &&
2935           (s->sew != MO_8) &&
2936           require_scale_zve32f(s) &&
2937           require_scale_zve64f(s);
2938}
2939
2940#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM)            \
2941static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2942{                                                                  \
2943    if (CHECK(s, a)) {                                             \
2944        if (FRM != RISCV_FRM_DYN) {                                \
2945            gen_set_rm(s, RISCV_FRM_DYN);                          \
2946        }                                                          \
2947                                                                   \
2948        uint32_t data = 0;                                         \
2949        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2950            gen_helper_##HELPER##_h,                               \
2951            gen_helper_##HELPER##_w,                               \
2952        };                                                         \
2953        TCGLabel *over = gen_new_label();                          \
2954        gen_set_rm(s, FRM);                                        \
2955        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2956        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2957                                                                   \
2958        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2959        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2960        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2961                           vreg_ofs(s, a->rs2), cpu_env,           \
2962                           s->cfg_ptr->vlen / 8,                   \
2963                           s->cfg_ptr->vlen / 8, data,             \
2964                           fns[s->sew - 1]);                       \
2965        mark_vs_dirty(s);                                          \
2966        gen_set_label(over);                                       \
2967        return true;                                               \
2968    }                                                              \
2969    return false;                                                  \
2970}
2971
2972GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w,
2973                      RISCV_FRM_DYN)
2974GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w,
2975                      RISCV_FRM_DYN)
2976GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
2977                      RISCV_FRM_DYN)
2978/* Reuse the helper function from vfncvt.f.f.w */
2979GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
2980                      RISCV_FRM_ROD)
2981
2982static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a)
2983{
2984    return require_rvv(s) &&
2985           require_scale_rvf(s) &&
2986           vext_check_isa_ill(s) &&
2987           /* OPFV narrowing instructions ignore vs1 check */
2988           vext_check_sd(s, a->rd, a->rs2, a->vm) &&
2989           require_scale_zve32f(s) &&
2990           require_scale_zve64f(s);
2991}
2992
2993#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM)                  \
2994static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2995{                                                                  \
2996    if (opxfv_narrow_check(s, a)) {                                \
2997        if (FRM != RISCV_FRM_DYN) {                                \
2998            gen_set_rm(s, RISCV_FRM_DYN);                          \
2999        }                                                          \
3000                                                                   \
3001        uint32_t data = 0;                                         \
3002        static gen_helper_gvec_3_ptr * const fns[3] = {            \
3003            gen_helper_##HELPER##_b,                               \
3004            gen_helper_##HELPER##_h,                               \
3005            gen_helper_##HELPER##_w,                               \
3006        };                                                         \
3007        TCGLabel *over = gen_new_label();                          \
3008        gen_set_rm(s, FRM);                                        \
3009        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3010        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
3011                                                                   \
3012        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
3013        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
3014                           vreg_ofs(s, a->rs2), cpu_env,           \
3015                           s->cfg_ptr->vlen / 8,                   \
3016                           s->cfg_ptr->vlen / 8, data,             \
3017                           fns[s->sew]);                           \
3018        mark_vs_dirty(s);                                          \
3019        gen_set_label(over);                                       \
3020        return true;                                               \
3021    }                                                              \
3022    return false;                                                  \
3023}
3024
3025GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN)
3026GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN)
3027/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */
3028GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ)
3029GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ)
3030
3031/*
3032 *** Vector Reduction Operations
3033 */
3034/* Vector Single-Width Integer Reduction Instructions */
3035static bool reduction_check(DisasContext *s, arg_rmrr *a)
3036{
3037    return require_rvv(s) &&
3038           vext_check_isa_ill(s) &&
3039           vext_check_reduction(s, a->rs2);
3040}
3041
3042GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
3043GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
3044GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
3045GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
3046GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
3047GEN_OPIVV_TRANS(vredand_vs, reduction_check)
3048GEN_OPIVV_TRANS(vredor_vs, reduction_check)
3049GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
3050
3051/* Vector Widening Integer Reduction Instructions */
3052static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
3053{
3054    return reduction_check(s, a) && (s->sew < MO_64) &&
3055           ((s->sew + 1) <= (s->cfg_ptr->elen >> 4));
3056}
3057
3058GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
3059GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
3060
3061/* Vector Single-Width Floating-Point Reduction Instructions */
3062static bool freduction_check(DisasContext *s, arg_rmrr *a)
3063{
3064    return reduction_check(s, a) &&
3065           require_rvf(s) &&
3066           require_zve32f(s) &&
3067           require_zve64f(s);
3068}
3069
3070GEN_OPFVV_TRANS(vfredsum_vs, freduction_check)
3071GEN_OPFVV_TRANS(vfredmax_vs, freduction_check)
3072GEN_OPFVV_TRANS(vfredmin_vs, freduction_check)
3073
3074/* Vector Widening Floating-Point Reduction Instructions */
3075static bool freduction_widen_check(DisasContext *s, arg_rmrr *a)
3076{
3077    return reduction_widen_check(s, a) &&
3078           require_scale_rvf(s) &&
3079           (s->sew != MO_8);
3080}
3081
3082GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check)
3083
3084/*
3085 *** Vector Mask Operations
3086 */
3087
3088/* Vector Mask-Register Logical Instructions */
3089#define GEN_MM_TRANS(NAME)                                         \
3090static bool trans_##NAME(DisasContext *s, arg_r *a)                \
3091{                                                                  \
3092    if (require_rvv(s) &&                                          \
3093        vext_check_isa_ill(s)) {                                   \
3094        uint32_t data = 0;                                         \
3095        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
3096        TCGLabel *over = gen_new_label();                          \
3097        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3098        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
3099                                                                   \
3100        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
3101        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
3102                           vreg_ofs(s, a->rs1),                    \
3103                           vreg_ofs(s, a->rs2), cpu_env,           \
3104                           s->cfg_ptr->vlen / 8,                   \
3105                           s->cfg_ptr->vlen / 8, data, fn);        \
3106        mark_vs_dirty(s);                                          \
3107        gen_set_label(over);                                       \
3108        return true;                                               \
3109    }                                                              \
3110    return false;                                                  \
3111}
3112
3113GEN_MM_TRANS(vmand_mm)
3114GEN_MM_TRANS(vmnand_mm)
3115GEN_MM_TRANS(vmandn_mm)
3116GEN_MM_TRANS(vmxor_mm)
3117GEN_MM_TRANS(vmor_mm)
3118GEN_MM_TRANS(vmnor_mm)
3119GEN_MM_TRANS(vmorn_mm)
3120GEN_MM_TRANS(vmxnor_mm)
3121
3122/* Vector count population in mask vcpop */
3123static bool trans_vcpop_m(DisasContext *s, arg_rmr *a)
3124{
3125    if (require_rvv(s) &&
3126        vext_check_isa_ill(s) &&
3127        s->vstart == 0) {
3128        TCGv_ptr src2, mask;
3129        TCGv dst;
3130        TCGv_i32 desc;
3131        uint32_t data = 0;
3132        data = FIELD_DP32(data, VDATA, VM, a->vm);
3133        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3134
3135        mask = tcg_temp_new_ptr();
3136        src2 = tcg_temp_new_ptr();
3137        dst = dest_gpr(s, a->rd);
3138        desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
3139                                          s->cfg_ptr->vlen / 8, data));
3140
3141        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
3142        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
3143
3144        gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc);
3145        gen_set_gpr(s, a->rd, dst);
3146
3147        tcg_temp_free_ptr(mask);
3148        tcg_temp_free_ptr(src2);
3149
3150        return true;
3151    }
3152    return false;
3153}
3154
3155/* vmfirst find-first-set mask bit */
3156static bool trans_vfirst_m(DisasContext *s, arg_rmr *a)
3157{
3158    if (require_rvv(s) &&
3159        vext_check_isa_ill(s) &&
3160        s->vstart == 0) {
3161        TCGv_ptr src2, mask;
3162        TCGv dst;
3163        TCGv_i32 desc;
3164        uint32_t data = 0;
3165        data = FIELD_DP32(data, VDATA, VM, a->vm);
3166        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3167
3168        mask = tcg_temp_new_ptr();
3169        src2 = tcg_temp_new_ptr();
3170        dst = dest_gpr(s, a->rd);
3171        desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
3172                                          s->cfg_ptr->vlen / 8, data));
3173
3174        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
3175        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
3176
3177        gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc);
3178        gen_set_gpr(s, a->rd, dst);
3179
3180        tcg_temp_free_ptr(mask);
3181        tcg_temp_free_ptr(src2);
3182        return true;
3183    }
3184    return false;
3185}
3186
3187/* vmsbf.m set-before-first mask bit */
3188/* vmsif.m set-includ-first mask bit */
3189/* vmsof.m set-only-first mask bit */
3190#define GEN_M_TRANS(NAME)                                          \
3191static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
3192{                                                                  \
3193    if (require_rvv(s) &&                                          \
3194        vext_check_isa_ill(s) &&                                   \
3195        require_vm(a->vm, a->rd) &&                                \
3196        (a->rd != a->rs2) &&                                       \
3197        (s->vstart == 0)) {                                        \
3198        uint32_t data = 0;                                         \
3199        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
3200        TCGLabel *over = gen_new_label();                          \
3201        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3202                                                                   \
3203        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
3204        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
3205        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
3206                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
3207                           cpu_env, s->cfg_ptr->vlen / 8,          \
3208                           s->cfg_ptr->vlen / 8,                   \
3209                           data, fn);                              \
3210        mark_vs_dirty(s);                                          \
3211        gen_set_label(over);                                       \
3212        return true;                                               \
3213    }                                                              \
3214    return false;                                                  \
3215}
3216
3217GEN_M_TRANS(vmsbf_m)
3218GEN_M_TRANS(vmsif_m)
3219GEN_M_TRANS(vmsof_m)
3220
3221/*
3222 * Vector Iota Instruction
3223 *
3224 * 1. The destination register cannot overlap the source register.
3225 * 2. If masked, cannot overlap the mask register ('v0').
3226 * 3. An illegal instruction exception is raised if vstart is non-zero.
3227 */
3228static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
3229{
3230    if (require_rvv(s) &&
3231        vext_check_isa_ill(s) &&
3232        !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) &&
3233        require_vm(a->vm, a->rd) &&
3234        require_align(a->rd, s->lmul) &&
3235        (s->vstart == 0)) {
3236        uint32_t data = 0;
3237        TCGLabel *over = gen_new_label();
3238        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3239
3240        data = FIELD_DP32(data, VDATA, VM, a->vm);
3241        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3242        static gen_helper_gvec_3_ptr * const fns[4] = {
3243            gen_helper_viota_m_b, gen_helper_viota_m_h,
3244            gen_helper_viota_m_w, gen_helper_viota_m_d,
3245        };
3246        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3247                           vreg_ofs(s, a->rs2), cpu_env,
3248                           s->cfg_ptr->vlen / 8,
3249                           s->cfg_ptr->vlen / 8, data, fns[s->sew]);
3250        mark_vs_dirty(s);
3251        gen_set_label(over);
3252        return true;
3253    }
3254    return false;
3255}
3256
3257/* Vector Element Index Instruction */
3258static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
3259{
3260    if (require_rvv(s) &&
3261        vext_check_isa_ill(s) &&
3262        require_align(a->rd, s->lmul) &&
3263        require_vm(a->vm, a->rd)) {
3264        uint32_t data = 0;
3265        TCGLabel *over = gen_new_label();
3266        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3267        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3268
3269        data = FIELD_DP32(data, VDATA, VM, a->vm);
3270        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3271        static gen_helper_gvec_2_ptr * const fns[4] = {
3272            gen_helper_vid_v_b, gen_helper_vid_v_h,
3273            gen_helper_vid_v_w, gen_helper_vid_v_d,
3274        };
3275        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3276                           cpu_env, s->cfg_ptr->vlen / 8,
3277                           s->cfg_ptr->vlen / 8,
3278                           data, fns[s->sew]);
3279        mark_vs_dirty(s);
3280        gen_set_label(over);
3281        return true;
3282    }
3283    return false;
3284}
3285
3286/*
3287 *** Vector Permutation Instructions
3288 */
3289
3290static void load_element(TCGv_i64 dest, TCGv_ptr base,
3291                         int ofs, int sew, bool sign)
3292{
3293    switch (sew) {
3294    case MO_8:
3295        if (!sign) {
3296            tcg_gen_ld8u_i64(dest, base, ofs);
3297        } else {
3298            tcg_gen_ld8s_i64(dest, base, ofs);
3299        }
3300        break;
3301    case MO_16:
3302        if (!sign) {
3303            tcg_gen_ld16u_i64(dest, base, ofs);
3304        } else {
3305            tcg_gen_ld16s_i64(dest, base, ofs);
3306        }
3307        break;
3308    case MO_32:
3309        if (!sign) {
3310            tcg_gen_ld32u_i64(dest, base, ofs);
3311        } else {
3312            tcg_gen_ld32s_i64(dest, base, ofs);
3313        }
3314        break;
3315    case MO_64:
3316        tcg_gen_ld_i64(dest, base, ofs);
3317        break;
3318    default:
3319        g_assert_not_reached();
3320        break;
3321    }
3322}
3323
3324/* offset of the idx element with base regsiter r */
3325static uint32_t endian_ofs(DisasContext *s, int r, int idx)
3326{
3327#if HOST_BIG_ENDIAN
3328    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
3329#else
3330    return vreg_ofs(s, r) + (idx << s->sew);
3331#endif
3332}
3333
3334/* adjust the index according to the endian */
3335static void endian_adjust(TCGv_i32 ofs, int sew)
3336{
3337#if HOST_BIG_ENDIAN
3338    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
3339#endif
3340}
3341
3342/* Load idx >= VLMAX ? 0 : vreg[idx] */
3343static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
3344                              int vreg, TCGv idx, int vlmax)
3345{
3346    TCGv_i32 ofs = tcg_temp_new_i32();
3347    TCGv_ptr base = tcg_temp_new_ptr();
3348    TCGv_i64 t_idx = tcg_temp_new_i64();
3349    TCGv_i64 t_vlmax, t_zero;
3350
3351    /*
3352     * Mask the index to the length so that we do
3353     * not produce an out-of-range load.
3354     */
3355    tcg_gen_trunc_tl_i32(ofs, idx);
3356    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
3357
3358    /* Convert the index to an offset. */
3359    endian_adjust(ofs, s->sew);
3360    tcg_gen_shli_i32(ofs, ofs, s->sew);
3361
3362    /* Convert the index to a pointer. */
3363    tcg_gen_ext_i32_ptr(base, ofs);
3364    tcg_gen_add_ptr(base, base, cpu_env);
3365
3366    /* Perform the load. */
3367    load_element(dest, base,
3368                 vreg_ofs(s, vreg), s->sew, false);
3369    tcg_temp_free_ptr(base);
3370    tcg_temp_free_i32(ofs);
3371
3372    /* Flush out-of-range indexing to zero.  */
3373    t_vlmax = tcg_constant_i64(vlmax);
3374    t_zero = tcg_constant_i64(0);
3375    tcg_gen_extu_tl_i64(t_idx, idx);
3376
3377    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
3378                        t_vlmax, dest, t_zero);
3379
3380    tcg_temp_free_i64(t_idx);
3381}
3382
3383static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
3384                              int vreg, int idx, bool sign)
3385{
3386    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign);
3387}
3388
3389/* Integer Scalar Move Instruction */
3390
3391static void store_element(TCGv_i64 val, TCGv_ptr base,
3392                          int ofs, int sew)
3393{
3394    switch (sew) {
3395    case MO_8:
3396        tcg_gen_st8_i64(val, base, ofs);
3397        break;
3398    case MO_16:
3399        tcg_gen_st16_i64(val, base, ofs);
3400        break;
3401    case MO_32:
3402        tcg_gen_st32_i64(val, base, ofs);
3403        break;
3404    case MO_64:
3405        tcg_gen_st_i64(val, base, ofs);
3406        break;
3407    default:
3408        g_assert_not_reached();
3409        break;
3410    }
3411}
3412
3413/*
3414 * Store vreg[idx] = val.
3415 * The index must be in range of VLMAX.
3416 */
3417static void vec_element_storei(DisasContext *s, int vreg,
3418                               int idx, TCGv_i64 val)
3419{
3420    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
3421}
3422
3423/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */
3424static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a)
3425{
3426    if (require_rvv(s) &&
3427        vext_check_isa_ill(s)) {
3428        TCGv_i64 t1;
3429        TCGv dest;
3430
3431        t1 = tcg_temp_new_i64();
3432        dest = tcg_temp_new();
3433        /*
3434         * load vreg and sign-extend to 64 bits,
3435         * then truncate to XLEN bits before storing to gpr.
3436         */
3437        vec_element_loadi(s, t1, a->rs2, 0, true);
3438        tcg_gen_trunc_i64_tl(dest, t1);
3439        gen_set_gpr(s, a->rd, dest);
3440        tcg_temp_free_i64(t1);
3441        tcg_temp_free(dest);
3442
3443        return true;
3444    }
3445    return false;
3446}
3447
3448/* vmv.s.x vd, rs1 # vd[0] = rs1 */
3449static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
3450{
3451    if (require_rvv(s) &&
3452        vext_check_isa_ill(s)) {
3453        /* This instruction ignores LMUL and vector register groups */
3454        TCGv_i64 t1;
3455        TCGv s1;
3456        TCGLabel *over = gen_new_label();
3457
3458        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3459        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3460
3461        t1 = tcg_temp_new_i64();
3462
3463        /*
3464         * load gpr and sign-extend to 64 bits,
3465         * then truncate to SEW bits when storing to vreg.
3466         */
3467        s1 = get_gpr(s, a->rs1, EXT_NONE);
3468        tcg_gen_ext_tl_i64(t1, s1);
3469        vec_element_storei(s, a->rd, 0, t1);
3470        tcg_temp_free_i64(t1);
3471        mark_vs_dirty(s);
3472        gen_set_label(over);
3473        return true;
3474    }
3475    return false;
3476}
3477
3478/* Floating-Point Scalar Move Instructions */
3479static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
3480{
3481    if (require_rvv(s) &&
3482        require_rvf(s) &&
3483        vext_check_isa_ill(s) &&
3484        require_zve32f(s) &&
3485        require_zve64f(s)) {
3486        gen_set_rm(s, RISCV_FRM_DYN);
3487
3488        unsigned int ofs = (8 << s->sew);
3489        unsigned int len = 64 - ofs;
3490        TCGv_i64 t_nan;
3491
3492        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false);
3493        /* NaN-box f[rd] as necessary for SEW */
3494        if (len) {
3495            t_nan = tcg_constant_i64(UINT64_MAX);
3496            tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
3497                                t_nan, ofs, len);
3498        }
3499
3500        mark_fs_dirty(s);
3501        return true;
3502    }
3503    return false;
3504}
3505
3506/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
3507static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
3508{
3509    if (require_rvv(s) &&
3510        require_rvf(s) &&
3511        vext_check_isa_ill(s) &&
3512        require_zve32f(s) &&
3513        require_zve64f(s)) {
3514        gen_set_rm(s, RISCV_FRM_DYN);
3515
3516        /* The instructions ignore LMUL and vector register group. */
3517        TCGv_i64 t1;
3518        TCGLabel *over = gen_new_label();
3519
3520        /* if vl == 0 or vstart >= vl, skip vector register write back */
3521        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3522        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3523
3524        /* NaN-box f[rs1] */
3525        t1 = tcg_temp_new_i64();
3526        do_nanbox(s, t1, cpu_fpr[a->rs1]);
3527
3528        vec_element_storei(s, a->rd, 0, t1);
3529        tcg_temp_free_i64(t1);
3530        mark_vs_dirty(s);
3531        gen_set_label(over);
3532        return true;
3533    }
3534    return false;
3535}
3536
3537/* Vector Slide Instructions */
3538static bool slideup_check(DisasContext *s, arg_rmrr *a)
3539{
3540    return require_rvv(s) &&
3541           vext_check_isa_ill(s) &&
3542           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
3543}
3544
3545GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
3546GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
3547GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
3548
3549static bool slidedown_check(DisasContext *s, arg_rmrr *a)
3550{
3551    return require_rvv(s) &&
3552           vext_check_isa_ill(s) &&
3553           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
3554}
3555
3556GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
3557GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
3558GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
3559
3560/* Vector Floating-Point Slide Instructions */
3561static bool fslideup_check(DisasContext *s, arg_rmrr *a)
3562{
3563    return slideup_check(s, a) &&
3564           require_rvf(s) &&
3565           require_zve32f(s) &&
3566           require_zve64f(s);
3567}
3568
3569static bool fslidedown_check(DisasContext *s, arg_rmrr *a)
3570{
3571    return slidedown_check(s, a) &&
3572           require_rvf(s) &&
3573           require_zve32f(s) &&
3574           require_zve64f(s);
3575}
3576
3577GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check)
3578GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check)
3579
3580/* Vector Register Gather Instruction */
3581static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
3582{
3583    return require_rvv(s) &&
3584           vext_check_isa_ill(s) &&
3585           require_align(a->rd, s->lmul) &&
3586           require_align(a->rs1, s->lmul) &&
3587           require_align(a->rs2, s->lmul) &&
3588           (a->rd != a->rs2 && a->rd != a->rs1) &&
3589           require_vm(a->vm, a->rd);
3590}
3591
3592static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a)
3593{
3594    int8_t emul = MO_16 - s->sew + s->lmul;
3595    return require_rvv(s) &&
3596           vext_check_isa_ill(s) &&
3597           (emul >= -3 && emul <= 3) &&
3598           require_align(a->rd, s->lmul) &&
3599           require_align(a->rs1, emul) &&
3600           require_align(a->rs2, s->lmul) &&
3601           (a->rd != a->rs2 && a->rd != a->rs1) &&
3602           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3603                          a->rs1, 1 << MAX(emul, 0)) &&
3604           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3605                          a->rs2, 1 << MAX(s->lmul, 0)) &&
3606           require_vm(a->vm, a->rd);
3607}
3608
3609GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
3610GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check)
3611
3612static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
3613{
3614    return require_rvv(s) &&
3615           vext_check_isa_ill(s) &&
3616           require_align(a->rd, s->lmul) &&
3617           require_align(a->rs2, s->lmul) &&
3618           (a->rd != a->rs2) &&
3619           require_vm(a->vm, a->rd);
3620}
3621
3622/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3623static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3624{
3625    if (!vrgather_vx_check(s, a)) {
3626        return false;
3627    }
3628
3629    if (a->vm && s->vl_eq_vlmax) {
3630        int scale = s->lmul - (s->sew + 3);
3631        int vlmax = s->cfg_ptr->vlen >> -scale;
3632        TCGv_i64 dest = tcg_temp_new_i64();
3633
3634        if (a->rs1 == 0) {
3635            vec_element_loadi(s, dest, a->rs2, 0, false);
3636        } else {
3637            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3638        }
3639
3640        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3641                             MAXSZ(s), MAXSZ(s), dest);
3642        tcg_temp_free_i64(dest);
3643        mark_vs_dirty(s);
3644    } else {
3645        static gen_helper_opivx * const fns[4] = {
3646            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3647            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3648        };
3649        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3650    }
3651    return true;
3652}
3653
3654/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3655static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3656{
3657    if (!vrgather_vx_check(s, a)) {
3658        return false;
3659    }
3660
3661    if (a->vm && s->vl_eq_vlmax) {
3662        int scale = s->lmul - (s->sew + 3);
3663        int vlmax = s->cfg_ptr->vlen >> -scale;
3664        if (a->rs1 >= vlmax) {
3665            tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd),
3666                                 MAXSZ(s), MAXSZ(s), 0);
3667        } else {
3668            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3669                                 endian_ofs(s, a->rs2, a->rs1),
3670                                 MAXSZ(s), MAXSZ(s));
3671        }
3672        mark_vs_dirty(s);
3673    } else {
3674        static gen_helper_opivx * const fns[4] = {
3675            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3676            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3677        };
3678        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3679                           s, IMM_ZX);
3680    }
3681    return true;
3682}
3683
3684/*
3685 * Vector Compress Instruction
3686 *
3687 * The destination vector register group cannot overlap the
3688 * source vector register group or the source mask register.
3689 */
3690static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3691{
3692    return require_rvv(s) &&
3693           vext_check_isa_ill(s) &&
3694           require_align(a->rd, s->lmul) &&
3695           require_align(a->rs2, s->lmul) &&
3696           (a->rd != a->rs2) &&
3697           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) &&
3698           (s->vstart == 0);
3699}
3700
3701static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3702{
3703    if (vcompress_vm_check(s, a)) {
3704        uint32_t data = 0;
3705        static gen_helper_gvec_4_ptr * const fns[4] = {
3706            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3707            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3708        };
3709        TCGLabel *over = gen_new_label();
3710        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3711
3712        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3713        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3714                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3715                           cpu_env, s->cfg_ptr->vlen / 8,
3716                           s->cfg_ptr->vlen / 8, data,
3717                           fns[s->sew]);
3718        mark_vs_dirty(s);
3719        gen_set_label(over);
3720        return true;
3721    }
3722    return false;
3723}
3724
3725/*
3726 * Whole Vector Register Move Instructions ignore vtype and vl setting.
3727 * Thus, we don't need to check vill bit. (Section 16.6)
3728 */
3729#define GEN_VMV_WHOLE_TRANS(NAME, LEN)                             \
3730static bool trans_##NAME(DisasContext *s, arg_##NAME * a)               \
3731{                                                                       \
3732    if (require_rvv(s) &&                                               \
3733        QEMU_IS_ALIGNED(a->rd, LEN) &&                                  \
3734        QEMU_IS_ALIGNED(a->rs2, LEN)) {                                 \
3735        uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN;                 \
3736        if (s->vstart == 0) {                                           \
3737            /* EEW = 8 */                                               \
3738            tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd),                  \
3739                             vreg_ofs(s, a->rs2), maxsz, maxsz);        \
3740            mark_vs_dirty(s);                                           \
3741        } else {                                                        \
3742            TCGLabel *over = gen_new_label();                           \
3743            tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over);  \
3744            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \
3745                               cpu_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \
3746            mark_vs_dirty(s);                                           \
3747            gen_set_label(over);                                        \
3748        }                                                               \
3749        return true;                                                    \
3750    }                                                                   \
3751    return false;                                                       \
3752}
3753
3754GEN_VMV_WHOLE_TRANS(vmv1r_v, 1)
3755GEN_VMV_WHOLE_TRANS(vmv2r_v, 2)
3756GEN_VMV_WHOLE_TRANS(vmv4r_v, 4)
3757GEN_VMV_WHOLE_TRANS(vmv8r_v, 8)
3758
3759static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div)
3760{
3761    uint8_t from = (s->sew + 3) - div;
3762    bool ret = require_rvv(s) &&
3763        (from >= 3 && from <= 8) &&
3764        (a->rd != a->rs2) &&
3765        require_align(a->rd, s->lmul) &&
3766        require_align(a->rs2, s->lmul - div) &&
3767        require_vm(a->vm, a->rd) &&
3768        require_noover(a->rd, s->lmul, a->rs2, s->lmul - div);
3769    return ret;
3770}
3771
3772static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
3773{
3774    uint32_t data = 0;
3775    gen_helper_gvec_3_ptr *fn;
3776    TCGLabel *over = gen_new_label();
3777    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3778    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3779
3780    static gen_helper_gvec_3_ptr * const fns[6][4] = {
3781        {
3782            NULL, gen_helper_vzext_vf2_h,
3783            gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d
3784        },
3785        {
3786            NULL, NULL,
3787            gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d,
3788        },
3789        {
3790            NULL, NULL,
3791            NULL, gen_helper_vzext_vf8_d
3792        },
3793        {
3794            NULL, gen_helper_vsext_vf2_h,
3795            gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d
3796        },
3797        {
3798            NULL, NULL,
3799            gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d,
3800        },
3801        {
3802            NULL, NULL,
3803            NULL, gen_helper_vsext_vf8_d
3804        }
3805    };
3806
3807    fn = fns[seq][s->sew];
3808    if (fn == NULL) {
3809        return false;
3810    }
3811
3812    data = FIELD_DP32(data, VDATA, VM, a->vm);
3813
3814    tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3815                       vreg_ofs(s, a->rs2), cpu_env,
3816                       s->cfg_ptr->vlen / 8,
3817                       s->cfg_ptr->vlen / 8, data, fn);
3818
3819    mark_vs_dirty(s);
3820    gen_set_label(over);
3821    return true;
3822}
3823
3824/* Vector Integer Extension */
3825#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ)             \
3826static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
3827{                                                     \
3828    if (int_ext_check(s, a, DIV)) {                   \
3829        return int_ext_op(s, a, SEQ);                 \
3830    }                                                 \
3831    return false;                                     \
3832}
3833
3834GEN_INT_EXT_TRANS(vzext_vf2, 1, 0)
3835GEN_INT_EXT_TRANS(vzext_vf4, 2, 1)
3836GEN_INT_EXT_TRANS(vzext_vf8, 3, 2)
3837GEN_INT_EXT_TRANS(vsext_vf2, 1, 3)
3838GEN_INT_EXT_TRANS(vsext_vf4, 2, 4)
3839GEN_INT_EXT_TRANS(vsext_vf8, 3, 5)
3840