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