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