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