1/*
2 * RISC-V translation routines for the RVV Standard Extension.
3 *
4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "tcg/tcg-op-gvec.h"
19#include "tcg/tcg-gvec-desc.h"
20#include "internals.h"
21
22static inline bool is_overlapped(const int8_t astart, int8_t asize,
23                                 const int8_t bstart, int8_t bsize)
24{
25    const int8_t aend = astart + asize;
26    const int8_t bend = bstart + bsize;
27
28    return MAX(aend, bend) - MIN(astart, bstart) < asize + bsize;
29}
30
31static bool require_rvv(DisasContext *s)
32{
33    return s->mstatus_vs != 0;
34}
35
36static bool require_rvf(DisasContext *s)
37{
38    if (s->mstatus_fs == 0) {
39        return false;
40    }
41
42    switch (s->sew) {
43    case MO_16:
44    case MO_32:
45        return has_ext(s, RVF);
46    case MO_64:
47        return has_ext(s, RVD);
48    default:
49        return false;
50    }
51}
52
53static bool require_scale_rvf(DisasContext *s)
54{
55    if (s->mstatus_fs == 0) {
56        return false;
57    }
58
59    switch (s->sew) {
60    case MO_8:
61    case MO_16:
62        return has_ext(s, RVF);
63    case MO_32:
64        return has_ext(s, RVD);
65    default:
66        return false;
67    }
68}
69
70/* Destination vector register group cannot overlap source mask register. */
71static bool require_vm(int vm, int vd)
72{
73    return (vm != 0 || vd != 0);
74}
75
76static bool require_nf(int vd, int nf, int lmul)
77{
78    int size = nf << MAX(lmul, 0);
79    return size <= 8 && vd + size <= 32;
80}
81
82/*
83 * Vector register should aligned with the passed-in LMUL (EMUL).
84 * If LMUL < 0, i.e. fractional LMUL, any vector register is allowed.
85 */
86static bool require_align(const int8_t val, const int8_t lmul)
87{
88    return lmul <= 0 || extract32(val, 0, lmul) == 0;
89}
90
91/*
92 * A destination vector register group can overlap a source vector
93 * register group only if one of the following holds:
94 *  1. The destination EEW equals the source EEW.
95 *  2. The destination EEW is smaller than the source EEW and the overlap
96 *     is in the lowest-numbered part of the source register group.
97 *  3. The destination EEW is greater than the source EEW, the source EMUL
98 *     is at least 1, and the overlap is in the highest-numbered part of
99 *     the destination register group.
100 * (Section 5.2)
101 *
102 * This function returns true if one of the following holds:
103 *  * Destination vector register group does not overlap a source vector
104 *    register group.
105 *  * Rule 3 met.
106 * For rule 1, overlap is allowed so this function doesn't need to be called.
107 * For rule 2, (vd == vs). Caller has to check whether: (vd != vs) before
108 * calling this function.
109 */
110static bool require_noover(const int8_t dst, const int8_t dst_lmul,
111                           const int8_t src, const int8_t src_lmul)
112{
113    int8_t dst_size = dst_lmul <= 0 ? 1 : 1 << dst_lmul;
114    int8_t src_size = src_lmul <= 0 ? 1 : 1 << src_lmul;
115
116    /* Destination EEW is greater than the source EEW, check rule 3. */
117    if (dst_size > src_size) {
118        if (dst < src &&
119            src_lmul >= 0 &&
120            is_overlapped(dst, dst_size, src, src_size) &&
121            !is_overlapped(dst, dst_size, src + src_size, src_size)) {
122            return true;
123        }
124    }
125
126    return !is_overlapped(dst, dst_size, src, src_size);
127}
128
129static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
130{
131    TCGv s1, dst;
132
133    if (!require_rvv(s) || !has_ext(s, RVV)) {
134        return false;
135    }
136
137    dst = dest_gpr(s, rd);
138
139    if (rd == 0 && rs1 == 0) {
140        s1 = tcg_temp_new();
141        tcg_gen_mov_tl(s1, cpu_vl);
142    } else if (rs1 == 0) {
143        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
144        s1 = tcg_constant_tl(RV_VLEN_MAX);
145    } else {
146        s1 = get_gpr(s, rs1, EXT_ZERO);
147    }
148
149    gen_helper_vsetvl(dst, cpu_env, s1, s2);
150    gen_set_gpr(s, rd, dst);
151    mark_vs_dirty(s);
152
153    tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn);
154    tcg_gen_lookup_and_goto_ptr();
155    s->base.is_jmp = DISAS_NORETURN;
156
157    if (rd == 0 && rs1 == 0) {
158        tcg_temp_free(s1);
159    }
160
161    return true;
162}
163
164static bool trans_vsetvl(DisasContext *s, arg_vsetvl *a)
165{
166    TCGv s2 = get_gpr(s, a->rs2, EXT_ZERO);
167    return do_vsetvl(s, a->rd, a->rs1, s2);
168}
169
170static bool trans_vsetvli(DisasContext *s, arg_vsetvli *a)
171{
172    TCGv s2 = tcg_constant_tl(a->zimm);
173    return do_vsetvl(s, a->rd, a->rs1, s2);
174}
175
176/* vector register offset from env */
177static uint32_t vreg_ofs(DisasContext *s, int reg)
178{
179    return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
180}
181
182/* check functions */
183
184/*
185 * Vector unit-stride, strided, unit-stride segment, strided segment
186 * store check function.
187 *
188 * Rules to be checked here:
189 *   1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3)
190 *   2. Destination vector register number is multiples of EMUL.
191 *      (Section 3.4.2, 7.3)
192 *   3. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8)
193 *   4. Vector register numbers accessed by the segment load or store
194 *      cannot increment past 31. (Section 7.8)
195 */
196static bool vext_check_store(DisasContext *s, int vd, int nf, uint8_t eew)
197{
198    int8_t emul = eew - s->sew + s->lmul;
199    return (emul >= -3 && emul <= 3) &&
200            require_align(vd, emul) &&
201            require_nf(vd, nf, emul);
202}
203
204/*
205 * Vector unit-stride, strided, unit-stride segment, strided segment
206 * load check function.
207 *
208 * Rules to be checked here:
209 *   1. All rules applies to store instructions are applies
210 *      to load instructions.
211 *   2. Destination vector register group for a masked vector
212 *      instruction cannot overlap the source mask register (v0).
213 *      (Section 5.3)
214 */
215static bool vext_check_load(DisasContext *s, int vd, int nf, int vm,
216                            uint8_t eew)
217{
218    return vext_check_store(s, vd, nf, eew) && require_vm(vm, vd);
219}
220
221/*
222 * Vector indexed, indexed segment store check function.
223 *
224 * Rules to be checked here:
225 *   1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3)
226 *   2. Index vector register number is multiples of EMUL.
227 *      (Section 3.4.2, 7.3)
228 *   3. Destination vector register number is multiples of LMUL.
229 *      (Section 3.4.2, 7.3)
230 *   4. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8)
231 *   5. Vector register numbers accessed by the segment load or store
232 *      cannot increment past 31. (Section 7.8)
233 */
234static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf,
235                                uint8_t eew)
236{
237    int8_t emul = eew - s->sew + s->lmul;
238    return (emul >= -3 && emul <= 3) &&
239            require_align(vs2, emul) &&
240            require_align(vd, s->lmul) &&
241            require_nf(vd, nf, s->lmul);
242}
243
244/*
245 * Vector indexed, indexed segment load check function.
246 *
247 * Rules to be checked here:
248 *   1. All rules applies to store instructions are applies
249 *      to load instructions.
250 *   2. Destination vector register group for a masked vector
251 *      instruction cannot overlap the source mask register (v0).
252 *      (Section 5.3)
253 *   3. Destination vector register cannot overlap a source vector
254 *      register (vs2) group.
255 *      (Section 5.2)
256 *   4. Destination vector register groups cannot overlap
257 *      the source vector register (vs2) group for
258 *      indexed segment load instructions. (Section 7.8.3)
259 */
260static bool vext_check_ld_index(DisasContext *s, int vd, int vs2,
261                                int nf, int vm, uint8_t eew)
262{
263    int8_t seg_vd;
264    int8_t emul = eew - s->sew + s->lmul;
265    bool ret = vext_check_st_index(s, vd, vs2, nf, eew) &&
266        require_vm(vm, vd);
267
268    /* Each segment register group has to follow overlap rules. */
269    for (int i = 0; i < nf; ++i) {
270        seg_vd = vd + (1 << MAX(s->lmul, 0)) * i;
271
272        if (eew > s->sew) {
273            if (seg_vd != vs2) {
274                ret &= require_noover(seg_vd, s->lmul, vs2, emul);
275            }
276        } else if (eew < s->sew) {
277            ret &= require_noover(seg_vd, s->lmul, vs2, emul);
278        }
279
280        /*
281         * Destination vector register groups cannot overlap
282         * the source vector register (vs2) group for
283         * indexed segment load instructions.
284         */
285        if (nf > 1) {
286            ret &= !is_overlapped(seg_vd, 1 << MAX(s->lmul, 0),
287                                  vs2, 1 << MAX(emul, 0));
288        }
289    }
290    return ret;
291}
292
293static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
294{
295    return require_vm(vm, vd) &&
296        require_align(vd, s->lmul) &&
297        require_align(vs, s->lmul);
298}
299
300/*
301 * Check function for vector instruction with format:
302 * single-width result and single-width sources (SEW = SEW op SEW)
303 *
304 * Rules to be checked here:
305 *   1. Destination vector register group for a masked vector
306 *      instruction cannot overlap the source mask register (v0).
307 *      (Section 5.3)
308 *   2. Destination vector register number is multiples of LMUL.
309 *      (Section 3.4.2)
310 *   3. Source (vs2, vs1) vector register number are multiples of LMUL.
311 *      (Section 3.4.2)
312 */
313static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm)
314{
315    return vext_check_ss(s, vd, vs2, vm) &&
316        require_align(vs1, s->lmul);
317}
318
319static bool vext_check_ms(DisasContext *s, int vd, int vs)
320{
321    bool ret = require_align(vs, s->lmul);
322    if (vd != vs) {
323        ret &= require_noover(vd, 0, vs, s->lmul);
324    }
325    return ret;
326}
327
328/*
329 * Check function for maskable vector instruction with format:
330 * single-width result and single-width sources (SEW = SEW op SEW)
331 *
332 * Rules to be checked here:
333 *   1. Source (vs2, vs1) vector register number are multiples of LMUL.
334 *      (Section 3.4.2)
335 *   2. Destination vector register cannot overlap a source vector
336 *      register (vs2, vs1) group.
337 *      (Section 5.2)
338 *   3. The destination vector register group for a masked vector
339 *      instruction cannot overlap the source mask register (v0),
340 *      unless the destination vector register is being written
341 *      with a mask value (e.g., comparisons) or the scalar result
342 *      of a reduction. (Section 5.3)
343 */
344static bool vext_check_mss(DisasContext *s, int vd, int vs1, int vs2)
345{
346    bool ret = vext_check_ms(s, vd, vs2) &&
347        require_align(vs1, s->lmul);
348    if (vd != vs1) {
349        ret &= require_noover(vd, 0, vs1, s->lmul);
350    }
351    return ret;
352}
353
354/*
355 * Common check function for vector widening instructions
356 * of double-width result (2*SEW).
357 *
358 * Rules to be checked here:
359 *   1. The largest vector register group used by an instruction
360 *      can not be greater than 8 vector registers (Section 5.2):
361 *      => LMUL < 8.
362 *      => SEW < 64.
363 *   2. Destination vector register number is multiples of 2 * LMUL.
364 *      (Section 3.4.2)
365 *   3. Destination vector register group for a masked vector
366 *      instruction cannot overlap the source mask register (v0).
367 *      (Section 5.3)
368 */
369static bool vext_wide_check_common(DisasContext *s, int vd, int vm)
370{
371    return (s->lmul <= 2) &&
372           (s->sew < MO_64) &&
373           require_align(vd, s->lmul + 1) &&
374           require_vm(vm, vd);
375}
376
377/*
378 * Common check function for vector narrowing instructions
379 * of single-width result (SEW) and double-width source (2*SEW).
380 *
381 * Rules to be checked here:
382 *   1. The largest vector register group used by an instruction
383 *      can not be greater than 8 vector registers (Section 5.2):
384 *      => LMUL < 8.
385 *      => SEW < 64.
386 *   2. Source vector register number is multiples of 2 * LMUL.
387 *      (Section 3.4.2)
388 *   3. Destination vector register number is multiples of LMUL.
389 *      (Section 3.4.2)
390 *   4. Destination vector register group for a masked vector
391 *      instruction cannot overlap the source mask register (v0).
392 *      (Section 5.3)
393 */
394static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2,
395                                     int vm)
396{
397    return (s->lmul <= 2) &&
398           (s->sew < MO_64) &&
399           require_align(vs2, s->lmul + 1) &&
400           require_align(vd, s->lmul) &&
401           require_vm(vm, vd);
402}
403
404static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
405{
406    return vext_wide_check_common(s, vd, vm) &&
407        require_align(vs, s->lmul) &&
408        require_noover(vd, s->lmul + 1, vs, s->lmul);
409}
410
411static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
412{
413    return vext_wide_check_common(s, vd, vm) &&
414        require_align(vs, s->lmul + 1);
415}
416
417/*
418 * Check function for vector instruction with format:
419 * double-width result and single-width sources (2*SEW = SEW op SEW)
420 *
421 * Rules to be checked here:
422 *   1. All rules in defined in widen common rules are applied.
423 *   2. Source (vs2, vs1) vector register number are multiples of LMUL.
424 *      (Section 3.4.2)
425 *   3. Destination vector register cannot overlap a source vector
426 *      register (vs2, vs1) group.
427 *      (Section 5.2)
428 */
429static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
430{
431    return vext_check_ds(s, vd, vs2, vm) &&
432        require_align(vs1, s->lmul) &&
433        require_noover(vd, s->lmul + 1, vs1, s->lmul);
434}
435
436/*
437 * Check function for vector instruction with format:
438 * double-width result and double-width source1 and single-width
439 * source2 (2*SEW = 2*SEW op SEW)
440 *
441 * Rules to be checked here:
442 *   1. All rules in defined in widen common rules are applied.
443 *   2. Source 1 (vs2) vector register number is multiples of 2 * LMUL.
444 *      (Section 3.4.2)
445 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
446 *      (Section 3.4.2)
447 *   4. Destination vector register cannot overlap a source vector
448 *      register (vs1) group.
449 *      (Section 5.2)
450 */
451static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm)
452{
453    return vext_check_ds(s, vd, vs1, vm) &&
454        require_align(vs2, s->lmul + 1);
455}
456
457static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
458{
459    bool ret = vext_narrow_check_common(s, vd, vs, vm);
460    if (vd != vs) {
461        ret &= require_noover(vd, s->lmul, vs, s->lmul + 1);
462    }
463    return ret;
464}
465
466/*
467 * Check function for vector instruction with format:
468 * single-width result and double-width source 1 and single-width
469 * source 2 (SEW = 2*SEW op SEW)
470 *
471 * Rules to be checked here:
472 *   1. All rules in defined in narrow common rules are applied.
473 *   2. Destination vector register cannot overlap a source vector
474 *      register (vs2) group.
475 *      (Section 5.2)
476 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
477 *      (Section 3.4.2)
478 */
479static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm)
480{
481    return vext_check_sd(s, vd, vs2, vm) &&
482        require_align(vs1, s->lmul);
483}
484
485/*
486 * Check function for vector reduction instructions.
487 *
488 * Rules to be checked here:
489 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
490 *      (Section 3.4.2)
491 */
492static bool vext_check_reduction(DisasContext *s, int vs2)
493{
494    return require_align(vs2, s->lmul);
495}
496
497/*
498 * Check function for vector slide instructions.
499 *
500 * Rules to be checked here:
501 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
502 *      (Section 3.4.2)
503 *   2. Destination vector register number is multiples of LMUL.
504 *      (Section 3.4.2)
505 *   3. Destination vector register group for a masked vector
506 *      instruction cannot overlap the source mask register (v0).
507 *      (Section 5.3)
508 *   4. The destination vector register group for vslideup, vslide1up,
509 *      vfslide1up, cannot overlap the source vector register (vs2) group.
510 *      (Section 5.2, 16.3.1, 16.3.3)
511 */
512static bool vext_check_slide(DisasContext *s, int vd, int vs2,
513                             int vm, bool is_over)
514{
515    bool ret = require_align(vs2, s->lmul) &&
516               require_align(vd, s->lmul) &&
517               require_vm(vm, vd);
518    if (is_over) {
519        ret &= (vd != vs2);
520    }
521    return ret;
522}
523
524/*
525 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
526 * So RVV is also be checked in this function.
527 */
528static bool vext_check_isa_ill(DisasContext *s)
529{
530    return !s->vill;
531}
532
533/* common translation macro */
534#define GEN_VEXT_TRANS(NAME, EEW, ARGTYPE, OP, CHECK)        \
535static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE * a) \
536{                                                            \
537    if (CHECK(s, a, EEW)) {                                  \
538        return OP(s, a, EEW);                                \
539    }                                                        \
540    return false;                                            \
541}
542
543/*
544 *** unit stride load and store
545 */
546typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
547                                TCGv_env, TCGv_i32);
548
549static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
550                          gen_helper_ldst_us *fn, DisasContext *s,
551                          bool is_store)
552{
553    TCGv_ptr dest, mask;
554    TCGv base;
555    TCGv_i32 desc;
556
557    TCGLabel *over = gen_new_label();
558    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
559
560    dest = tcg_temp_new_ptr();
561    mask = tcg_temp_new_ptr();
562    base = get_gpr(s, rs1, EXT_NONE);
563
564    /*
565     * As simd_desc supports at most 256 bytes, and in this implementation,
566     * the max vector group length is 2048 bytes. So split it into two parts.
567     *
568     * The first part is vlen in bytes, encoded in maxsz of simd_desc.
569     * The second part is lmul, encoded in data of simd_desc.
570     */
571    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
572
573    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
574    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
575
576    fn(dest, mask, base, cpu_env, desc);
577
578    tcg_temp_free_ptr(dest);
579    tcg_temp_free_ptr(mask);
580
581    if (!is_store) {
582        mark_vs_dirty(s);
583    }
584
585    gen_set_label(over);
586    return true;
587}
588
589static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
590{
591    uint32_t data = 0;
592    gen_helper_ldst_us *fn;
593    static gen_helper_ldst_us * const fns[2][4] = {
594        /* masked unit stride load */
595        { gen_helper_vle8_v_mask, gen_helper_vle16_v_mask,
596          gen_helper_vle32_v_mask, gen_helper_vle64_v_mask },
597        /* unmasked unit stride load */
598        { gen_helper_vle8_v, gen_helper_vle16_v,
599          gen_helper_vle32_v, gen_helper_vle64_v }
600    };
601
602    fn =  fns[a->vm][eew];
603    if (fn == NULL) {
604        return false;
605    }
606
607    data = FIELD_DP32(data, VDATA, VM, a->vm);
608    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
609    data = FIELD_DP32(data, VDATA, NF, a->nf);
610    return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
611}
612
613static bool ld_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew)
614{
615    return require_rvv(s) &&
616           vext_check_isa_ill(s) &&
617           vext_check_load(s, a->rd, a->nf, a->vm, eew);
618}
619
620GEN_VEXT_TRANS(vle8_v,  MO_8,  r2nfvm, ld_us_op, ld_us_check)
621GEN_VEXT_TRANS(vle16_v, MO_16, r2nfvm, ld_us_op, ld_us_check)
622GEN_VEXT_TRANS(vle32_v, MO_32, r2nfvm, ld_us_op, ld_us_check)
623GEN_VEXT_TRANS(vle64_v, MO_64, r2nfvm, ld_us_op, ld_us_check)
624
625static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
626{
627    uint32_t data = 0;
628    gen_helper_ldst_us *fn;
629    static gen_helper_ldst_us * const fns[2][4] = {
630        /* masked unit stride store */
631        { gen_helper_vse8_v_mask, gen_helper_vse16_v_mask,
632          gen_helper_vse32_v_mask, gen_helper_vse64_v_mask },
633        /* unmasked unit stride store */
634        { gen_helper_vse8_v, gen_helper_vse16_v,
635          gen_helper_vse32_v, gen_helper_vse64_v }
636    };
637
638    fn =  fns[a->vm][eew];
639    if (fn == NULL) {
640        return false;
641    }
642
643    data = FIELD_DP32(data, VDATA, VM, a->vm);
644    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
645    data = FIELD_DP32(data, VDATA, NF, a->nf);
646    return ldst_us_trans(a->rd, a->rs1, data, fn, s, true);
647}
648
649static bool st_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew)
650{
651    return require_rvv(s) &&
652           vext_check_isa_ill(s) &&
653           vext_check_store(s, a->rd, a->nf, eew);
654}
655
656GEN_VEXT_TRANS(vse8_v,  MO_8,  r2nfvm, st_us_op, st_us_check)
657GEN_VEXT_TRANS(vse16_v, MO_16, r2nfvm, st_us_op, st_us_check)
658GEN_VEXT_TRANS(vse32_v, MO_32, r2nfvm, st_us_op, st_us_check)
659GEN_VEXT_TRANS(vse64_v, MO_64, r2nfvm, st_us_op, st_us_check)
660
661/*
662 *** stride load and store
663 */
664typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
665                                    TCGv, TCGv_env, TCGv_i32);
666
667static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
668                              uint32_t data, gen_helper_ldst_stride *fn,
669                              DisasContext *s, bool is_store)
670{
671    TCGv_ptr dest, mask;
672    TCGv base, stride;
673    TCGv_i32 desc;
674
675    TCGLabel *over = gen_new_label();
676    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
677
678    dest = tcg_temp_new_ptr();
679    mask = tcg_temp_new_ptr();
680    base = get_gpr(s, rs1, EXT_NONE);
681    stride = get_gpr(s, rs2, EXT_NONE);
682    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
683
684    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
685    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
686
687    fn(dest, mask, base, stride, cpu_env, desc);
688
689    tcg_temp_free_ptr(dest);
690    tcg_temp_free_ptr(mask);
691
692    if (!is_store) {
693        mark_vs_dirty(s);
694    }
695
696    gen_set_label(over);
697    return true;
698}
699
700static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
701{
702    uint32_t data = 0;
703    gen_helper_ldst_stride *fn;
704    static gen_helper_ldst_stride * const fns[4] = {
705        gen_helper_vlse8_v, gen_helper_vlse16_v,
706        gen_helper_vlse32_v, gen_helper_vlse64_v
707    };
708
709    fn = fns[eew];
710    if (fn == NULL) {
711        return false;
712    }
713
714    data = FIELD_DP32(data, VDATA, VM, a->vm);
715    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
716    data = FIELD_DP32(data, VDATA, NF, a->nf);
717    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
718}
719
720static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
721{
722    return require_rvv(s) &&
723           vext_check_isa_ill(s) &&
724           vext_check_load(s, a->rd, a->nf, a->vm, eew);
725}
726
727GEN_VEXT_TRANS(vlse8_v,  MO_8,  rnfvm, ld_stride_op, ld_stride_check)
728GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check)
729GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check)
730GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check)
731
732static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
733{
734    uint32_t data = 0;
735    gen_helper_ldst_stride *fn;
736    static gen_helper_ldst_stride * const fns[4] = {
737        /* masked stride store */
738        gen_helper_vsse8_v,  gen_helper_vsse16_v,
739        gen_helper_vsse32_v,  gen_helper_vsse64_v
740    };
741
742    data = FIELD_DP32(data, VDATA, VM, a->vm);
743    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
744    data = FIELD_DP32(data, VDATA, NF, a->nf);
745    fn = fns[eew];
746    if (fn == NULL) {
747        return false;
748    }
749
750    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
751}
752
753static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
754{
755    return require_rvv(s) &&
756           vext_check_isa_ill(s) &&
757           vext_check_store(s, a->rd, a->nf, eew);
758}
759
760GEN_VEXT_TRANS(vsse8_v,  MO_8,  rnfvm, st_stride_op, st_stride_check)
761GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check)
762GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check)
763GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check)
764
765/*
766 *** index load and store
767 */
768typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
769                                   TCGv_ptr, TCGv_env, TCGv_i32);
770
771static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
772                             uint32_t data, gen_helper_ldst_index *fn,
773                             DisasContext *s, bool is_store)
774{
775    TCGv_ptr dest, mask, index;
776    TCGv base;
777    TCGv_i32 desc;
778
779    TCGLabel *over = gen_new_label();
780    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
781
782    dest = tcg_temp_new_ptr();
783    mask = tcg_temp_new_ptr();
784    index = tcg_temp_new_ptr();
785    base = get_gpr(s, rs1, EXT_NONE);
786    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
787
788    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
789    tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
790    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
791
792    fn(dest, mask, base, index, cpu_env, desc);
793
794    tcg_temp_free_ptr(dest);
795    tcg_temp_free_ptr(mask);
796    tcg_temp_free_ptr(index);
797
798    if (!is_store) {
799        mark_vs_dirty(s);
800    }
801
802    gen_set_label(over);
803    return true;
804}
805
806static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
807{
808    uint32_t data = 0;
809    gen_helper_ldst_index *fn;
810    static gen_helper_ldst_index * const fns[7][4] = {
811        { gen_helper_vlxb_v_b,  gen_helper_vlxb_v_h,
812          gen_helper_vlxb_v_w,  gen_helper_vlxb_v_d },
813        { NULL,                 gen_helper_vlxh_v_h,
814          gen_helper_vlxh_v_w,  gen_helper_vlxh_v_d },
815        { NULL,                 NULL,
816          gen_helper_vlxw_v_w,  gen_helper_vlxw_v_d },
817        { gen_helper_vlxe_v_b,  gen_helper_vlxe_v_h,
818          gen_helper_vlxe_v_w,  gen_helper_vlxe_v_d },
819        { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h,
820          gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d },
821        { NULL,                 gen_helper_vlxhu_v_h,
822          gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d },
823        { NULL,                 NULL,
824          gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d },
825    };
826
827    fn =  fns[seq][s->sew];
828    if (fn == NULL) {
829        return false;
830    }
831
832    data = FIELD_DP32(data, VDATA, VM, a->vm);
833    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
834    data = FIELD_DP32(data, VDATA, NF, a->nf);
835    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
836}
837
838/*
839 * For vector indexed segment loads, the destination vector register
840 * groups cannot overlap the source vector register group (specified by
841 * `vs2`), else an illegal instruction exception is raised.
842 */
843static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
844{
845    return require_rvv(s) &&
846           vext_check_isa_ill(s) &&
847           vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew);
848}
849
850GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check)
851GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check)
852GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check)
853GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check)
854GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check)
855GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check)
856GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check)
857
858static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
859{
860    uint32_t data = 0;
861    gen_helper_ldst_index *fn;
862    static gen_helper_ldst_index * const fns[4][4] = {
863        { gen_helper_vsxb_v_b,  gen_helper_vsxb_v_h,
864          gen_helper_vsxb_v_w,  gen_helper_vsxb_v_d },
865        { NULL,                 gen_helper_vsxh_v_h,
866          gen_helper_vsxh_v_w,  gen_helper_vsxh_v_d },
867        { NULL,                 NULL,
868          gen_helper_vsxw_v_w,  gen_helper_vsxw_v_d },
869        { gen_helper_vsxe_v_b,  gen_helper_vsxe_v_h,
870          gen_helper_vsxe_v_w,  gen_helper_vsxe_v_d }
871    };
872
873    fn =  fns[seq][s->sew];
874    if (fn == NULL) {
875        return false;
876    }
877
878    data = FIELD_DP32(data, VDATA, VM, a->vm);
879    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
880    data = FIELD_DP32(data, VDATA, NF, a->nf);
881    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
882}
883
884static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
885{
886    return require_rvv(s) &&
887           vext_check_isa_ill(s) &&
888           vext_check_st_index(s, a->rd, a->rs2, a->nf, eew);
889}
890
891GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check)
892GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check)
893GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check)
894GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check)
895
896/*
897 *** unit stride fault-only-first load
898 */
899static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
900                       gen_helper_ldst_us *fn, DisasContext *s)
901{
902    TCGv_ptr dest, mask;
903    TCGv base;
904    TCGv_i32 desc;
905
906    TCGLabel *over = gen_new_label();
907    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
908
909    dest = tcg_temp_new_ptr();
910    mask = tcg_temp_new_ptr();
911    base = get_gpr(s, rs1, EXT_NONE);
912    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
913
914    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
915    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
916
917    fn(dest, mask, base, cpu_env, desc);
918
919    tcg_temp_free_ptr(dest);
920    tcg_temp_free_ptr(mask);
921    mark_vs_dirty(s);
922    gen_set_label(over);
923    return true;
924}
925
926static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
927{
928    uint32_t data = 0;
929    gen_helper_ldst_us *fn;
930    static gen_helper_ldst_us * const fns[7][4] = {
931        { gen_helper_vlbff_v_b,  gen_helper_vlbff_v_h,
932          gen_helper_vlbff_v_w,  gen_helper_vlbff_v_d },
933        { NULL,                  gen_helper_vlhff_v_h,
934          gen_helper_vlhff_v_w,  gen_helper_vlhff_v_d },
935        { NULL,                  NULL,
936          gen_helper_vlwff_v_w,  gen_helper_vlwff_v_d },
937        { gen_helper_vleff_v_b,  gen_helper_vleff_v_h,
938          gen_helper_vleff_v_w,  gen_helper_vleff_v_d },
939        { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h,
940          gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d },
941        { NULL,                  gen_helper_vlhuff_v_h,
942          gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d },
943        { NULL,                  NULL,
944          gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d }
945    };
946
947    fn =  fns[seq][s->sew];
948    if (fn == NULL) {
949        return false;
950    }
951
952    data = FIELD_DP32(data, VDATA, VM, a->vm);
953    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
954    data = FIELD_DP32(data, VDATA, NF, a->nf);
955    return ldff_trans(a->rd, a->rs1, data, fn, s);
956}
957
958GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check)
959GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check)
960GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check)
961GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check)
962GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check)
963GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check)
964GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check)
965
966/*
967 *** Vector Integer Arithmetic Instructions
968 */
969#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
970
971static bool opivv_check(DisasContext *s, arg_rmrr *a)
972{
973    return require_rvv(s) &&
974           vext_check_isa_ill(s) &&
975           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
976}
977
978typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
979                        uint32_t, uint32_t, uint32_t);
980
981static inline bool
982do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
983              gen_helper_gvec_4_ptr *fn)
984{
985    TCGLabel *over = gen_new_label();
986    if (!opivv_check(s, a)) {
987        return false;
988    }
989
990    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
991
992    if (a->vm && s->vl_eq_vlmax) {
993        gvec_fn(s->sew, vreg_ofs(s, a->rd),
994                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
995                MAXSZ(s), MAXSZ(s));
996    } else {
997        uint32_t data = 0;
998
999        data = FIELD_DP32(data, VDATA, VM, a->vm);
1000        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1001        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1002                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
1003                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1004    }
1005    mark_vs_dirty(s);
1006    gen_set_label(over);
1007    return true;
1008}
1009
1010/* OPIVV with GVEC IR */
1011#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
1012static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1013{                                                                  \
1014    static gen_helper_gvec_4_ptr * const fns[4] = {                \
1015        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1016        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1017    };                                                             \
1018    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1019}
1020
1021GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
1022GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
1023
1024typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
1025                              TCGv_env, TCGv_i32);
1026
1027static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
1028                        gen_helper_opivx *fn, DisasContext *s)
1029{
1030    TCGv_ptr dest, src2, mask;
1031    TCGv src1;
1032    TCGv_i32 desc;
1033    uint32_t data = 0;
1034
1035    TCGLabel *over = gen_new_label();
1036    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1037
1038    dest = tcg_temp_new_ptr();
1039    mask = tcg_temp_new_ptr();
1040    src2 = tcg_temp_new_ptr();
1041    src1 = get_gpr(s, rs1, EXT_NONE);
1042
1043    data = FIELD_DP32(data, VDATA, VM, vm);
1044    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1045    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1046
1047    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1048    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1049    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1050
1051    fn(dest, mask, src1, src2, cpu_env, desc);
1052
1053    tcg_temp_free_ptr(dest);
1054    tcg_temp_free_ptr(mask);
1055    tcg_temp_free_ptr(src2);
1056    mark_vs_dirty(s);
1057    gen_set_label(over);
1058    return true;
1059}
1060
1061static bool opivx_check(DisasContext *s, arg_rmrr *a)
1062{
1063    return require_rvv(s) &&
1064           vext_check_isa_ill(s) &&
1065           vext_check_ss(s, a->rd, a->rs2, a->vm);
1066}
1067
1068typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
1069                         uint32_t, uint32_t);
1070
1071static inline bool
1072do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
1073              gen_helper_opivx *fn)
1074{
1075    if (!opivx_check(s, a)) {
1076        return false;
1077    }
1078
1079    if (a->vm && s->vl_eq_vlmax) {
1080        TCGv_i64 src1 = tcg_temp_new_i64();
1081
1082        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
1083        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1084                src1, MAXSZ(s), MAXSZ(s));
1085
1086        tcg_temp_free_i64(src1);
1087        mark_vs_dirty(s);
1088        return true;
1089    }
1090    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1091}
1092
1093/* OPIVX with GVEC IR */
1094#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
1095static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1096{                                                                  \
1097    static gen_helper_opivx * const fns[4] = {                     \
1098        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1099        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1100    };                                                             \
1101    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1102}
1103
1104GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
1105GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
1106
1107static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1108{
1109    tcg_gen_vec_sub8_i64(d, b, a);
1110}
1111
1112static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1113{
1114    tcg_gen_vec_sub16_i64(d, b, a);
1115}
1116
1117static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1118{
1119    tcg_gen_sub_i32(ret, arg2, arg1);
1120}
1121
1122static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1123{
1124    tcg_gen_sub_i64(ret, arg2, arg1);
1125}
1126
1127static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
1128{
1129    tcg_gen_sub_vec(vece, r, b, a);
1130}
1131
1132static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
1133                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
1134{
1135    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
1136    static const GVecGen2s rsub_op[4] = {
1137        { .fni8 = gen_vec_rsub8_i64,
1138          .fniv = gen_rsub_vec,
1139          .fno = gen_helper_vec_rsubs8,
1140          .opt_opc = vecop_list,
1141          .vece = MO_8 },
1142        { .fni8 = gen_vec_rsub16_i64,
1143          .fniv = gen_rsub_vec,
1144          .fno = gen_helper_vec_rsubs16,
1145          .opt_opc = vecop_list,
1146          .vece = MO_16 },
1147        { .fni4 = gen_rsub_i32,
1148          .fniv = gen_rsub_vec,
1149          .fno = gen_helper_vec_rsubs32,
1150          .opt_opc = vecop_list,
1151          .vece = MO_32 },
1152        { .fni8 = gen_rsub_i64,
1153          .fniv = gen_rsub_vec,
1154          .fno = gen_helper_vec_rsubs64,
1155          .opt_opc = vecop_list,
1156          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
1157          .vece = MO_64 },
1158    };
1159
1160    tcg_debug_assert(vece <= MO_64);
1161    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
1162}
1163
1164GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1165
1166typedef enum {
1167    IMM_ZX,         /* Zero-extended */
1168    IMM_SX,         /* Sign-extended */
1169    IMM_TRUNC_SEW,  /* Truncate to log(SEW) bits */
1170    IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */
1171} imm_mode_t;
1172
1173static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode)
1174{
1175    switch (imm_mode) {
1176    case IMM_ZX:
1177        return extract64(imm, 0, 5);
1178    case IMM_SX:
1179        return sextract64(imm, 0, 5);
1180    case IMM_TRUNC_SEW:
1181        return extract64(imm, 0, s->sew + 3);
1182    case IMM_TRUNC_2SEW:
1183        return extract64(imm, 0, s->sew + 4);
1184    default:
1185        g_assert_not_reached();
1186    }
1187}
1188
1189static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1190                        gen_helper_opivx *fn, DisasContext *s,
1191                        imm_mode_t imm_mode)
1192{
1193    TCGv_ptr dest, src2, mask;
1194    TCGv src1;
1195    TCGv_i32 desc;
1196    uint32_t data = 0;
1197
1198    TCGLabel *over = gen_new_label();
1199    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1200
1201    dest = tcg_temp_new_ptr();
1202    mask = tcg_temp_new_ptr();
1203    src2 = tcg_temp_new_ptr();
1204    src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode));
1205
1206    data = FIELD_DP32(data, VDATA, VM, vm);
1207    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1208    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1209
1210    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1211    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1212    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1213
1214    fn(dest, mask, src1, src2, cpu_env, desc);
1215
1216    tcg_temp_free_ptr(dest);
1217    tcg_temp_free_ptr(mask);
1218    tcg_temp_free_ptr(src2);
1219    mark_vs_dirty(s);
1220    gen_set_label(over);
1221    return true;
1222}
1223
1224typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1225                         uint32_t, uint32_t);
1226
1227static inline bool
1228do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1229              gen_helper_opivx *fn, imm_mode_t imm_mode)
1230{
1231    if (!opivx_check(s, a)) {
1232        return false;
1233    }
1234
1235    if (a->vm && s->vl_eq_vlmax) {
1236        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1237                extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
1238        mark_vs_dirty(s);
1239        return true;
1240    }
1241    return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode);
1242}
1243
1244/* OPIVI with GVEC IR */
1245#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \
1246static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1247{                                                                  \
1248    static gen_helper_opivx * const fns[4] = {                     \
1249        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1250        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1251    };                                                             \
1252    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1253                         fns[s->sew], IMM_MODE);                   \
1254}
1255
1256GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi)
1257
1258static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1259                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1260{
1261    TCGv_i64 tmp = tcg_constant_i64(c);
1262    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1263}
1264
1265GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi)
1266
1267/* Vector Widening Integer Add/Subtract */
1268
1269/* OPIVV with WIDEN */
1270static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1271{
1272    return require_rvv(s) &&
1273           vext_check_isa_ill(s) &&
1274           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
1275}
1276
1277static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1278                           gen_helper_gvec_4_ptr *fn,
1279                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1280{
1281    if (checkfn(s, a)) {
1282        uint32_t data = 0;
1283        TCGLabel *over = gen_new_label();
1284        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1285
1286        data = FIELD_DP32(data, VDATA, VM, a->vm);
1287        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1288        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1289                           vreg_ofs(s, a->rs1),
1290                           vreg_ofs(s, a->rs2),
1291                           cpu_env, s->vlen / 8, s->vlen / 8,
1292                           data, fn);
1293        mark_vs_dirty(s);
1294        gen_set_label(over);
1295        return true;
1296    }
1297    return false;
1298}
1299
1300#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1301static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1302{                                                            \
1303    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1304        gen_helper_##NAME##_b,                               \
1305        gen_helper_##NAME##_h,                               \
1306        gen_helper_##NAME##_w                                \
1307    };                                                       \
1308    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1309}
1310
1311GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1312GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1313GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1314GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1315
1316/* OPIVX with WIDEN */
1317static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1318{
1319    return require_rvv(s) &&
1320           vext_check_isa_ill(s) &&
1321           vext_check_ds(s, a->rd, a->rs2, a->vm);
1322}
1323
1324static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1325                           gen_helper_opivx *fn)
1326{
1327    if (opivx_widen_check(s, a)) {
1328        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1329    }
1330    return false;
1331}
1332
1333#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1334static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1335{                                                            \
1336    static gen_helper_opivx * const fns[3] = {               \
1337        gen_helper_##NAME##_b,                               \
1338        gen_helper_##NAME##_h,                               \
1339        gen_helper_##NAME##_w                                \
1340    };                                                       \
1341    return do_opivx_widen(s, a, fns[s->sew]);                \
1342}
1343
1344GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1345GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1346GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1347GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1348
1349/* WIDEN OPIVV with WIDEN */
1350static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1351{
1352    return require_rvv(s) &&
1353           vext_check_isa_ill(s) &&
1354           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
1355}
1356
1357static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1358                           gen_helper_gvec_4_ptr *fn)
1359{
1360    if (opiwv_widen_check(s, a)) {
1361        uint32_t data = 0;
1362        TCGLabel *over = gen_new_label();
1363        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1364
1365        data = FIELD_DP32(data, VDATA, VM, a->vm);
1366        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1367        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1368                           vreg_ofs(s, a->rs1),
1369                           vreg_ofs(s, a->rs2),
1370                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1371        mark_vs_dirty(s);
1372        gen_set_label(over);
1373        return true;
1374    }
1375    return false;
1376}
1377
1378#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1379static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1380{                                                            \
1381    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1382        gen_helper_##NAME##_b,                               \
1383        gen_helper_##NAME##_h,                               \
1384        gen_helper_##NAME##_w                                \
1385    };                                                       \
1386    return do_opiwv_widen(s, a, fns[s->sew]);                \
1387}
1388
1389GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1390GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1391GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1392GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1393
1394/* WIDEN OPIVX with WIDEN */
1395static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1396{
1397    return require_rvv(s) &&
1398           vext_check_isa_ill(s) &&
1399           vext_check_dd(s, a->rd, a->rs2, a->vm);
1400}
1401
1402static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1403                           gen_helper_opivx *fn)
1404{
1405    if (opiwx_widen_check(s, a)) {
1406        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1407    }
1408    return false;
1409}
1410
1411#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1412static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1413{                                                            \
1414    static gen_helper_opivx * const fns[3] = {               \
1415        gen_helper_##NAME##_b,                               \
1416        gen_helper_##NAME##_h,                               \
1417        gen_helper_##NAME##_w                                \
1418    };                                                       \
1419    return do_opiwx_widen(s, a, fns[s->sew]);                \
1420}
1421
1422GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1423GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1424GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1425GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1426
1427/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1428/* OPIVV without GVEC IR */
1429#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1430static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1431{                                                                  \
1432    if (CHECK(s, a)) {                                             \
1433        uint32_t data = 0;                                         \
1434        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1435            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1436            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1437        };                                                         \
1438        TCGLabel *over = gen_new_label();                          \
1439        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1440                                                                   \
1441        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1442        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1443        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1444                           vreg_ofs(s, a->rs1),                    \
1445                           vreg_ofs(s, a->rs2), cpu_env,           \
1446                           s->vlen / 8, s->vlen / 8, data,         \
1447                           fns[s->sew]);                           \
1448        mark_vs_dirty(s);                                          \
1449        gen_set_label(over);                                       \
1450        return true;                                               \
1451    }                                                              \
1452    return false;                                                  \
1453}
1454
1455/*
1456 * For vadc and vsbc, an illegal instruction exception is raised if the
1457 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1458 */
1459static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1460{
1461    return require_rvv(s) &&
1462           vext_check_isa_ill(s) &&
1463           (a->rd != 0) &&
1464           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1465}
1466
1467GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1468GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1469
1470/*
1471 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1472 * destination vector register overlaps a source vector register group.
1473 */
1474static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1475{
1476    return require_rvv(s) &&
1477           vext_check_isa_ill(s) &&
1478           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1479}
1480
1481GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1482GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1483
1484static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1485{
1486    return require_rvv(s) &&
1487           vext_check_isa_ill(s) &&
1488           (a->rd != 0) &&
1489           vext_check_ss(s, a->rd, a->rs2, a->vm);
1490}
1491
1492/* OPIVX without GVEC IR */
1493#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1494static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1495{                                                                        \
1496    if (CHECK(s, a)) {                                                   \
1497        static gen_helper_opivx * const fns[4] = {                       \
1498            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1499            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1500        };                                                               \
1501                                                                         \
1502        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1503    }                                                                    \
1504    return false;                                                        \
1505}
1506
1507GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1508GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1509
1510static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1511{
1512    return require_rvv(s) &&
1513           vext_check_isa_ill(s) &&
1514           vext_check_ms(s, a->rd, a->rs2);
1515}
1516
1517GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1518GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1519
1520/* OPIVI without GVEC IR */
1521#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK)                    \
1522static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1523{                                                                        \
1524    if (CHECK(s, a)) {                                                   \
1525        static gen_helper_opivx * const fns[4] = {                       \
1526            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1527            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1528        };                                                               \
1529        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1530                           fns[s->sew], s, IMM_MODE);                    \
1531    }                                                                    \
1532    return false;                                                        \
1533}
1534
1535GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check)
1536GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check)
1537
1538/* Vector Bitwise Logical Instructions */
1539GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1540GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1541GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1542GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1543GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1544GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1545GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi)
1546GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx,  ori)
1547GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori)
1548
1549/* Vector Single-Width Bit Shift Instructions */
1550GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1551GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1552GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1553
1554typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1555                           uint32_t, uint32_t);
1556
1557static inline bool
1558do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1559                    gen_helper_opivx *fn)
1560{
1561    if (!opivx_check(s, a)) {
1562        return false;
1563    }
1564
1565    if (a->vm && s->vl_eq_vlmax) {
1566        TCGv_i32 src1 = tcg_temp_new_i32();
1567
1568        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1569        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1570        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1571                src1, MAXSZ(s), MAXSZ(s));
1572
1573        tcg_temp_free_i32(src1);
1574        mark_vs_dirty(s);
1575        return true;
1576    }
1577    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1578}
1579
1580#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1581static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1582{                                                                         \
1583    static gen_helper_opivx * const fns[4] = {                            \
1584        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1585        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1586    };                                                                    \
1587                                                                          \
1588    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1589}
1590
1591GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1592GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1593GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1594
1595GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_ZX, vsll_vx, shli)
1596GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_ZX, vsrl_vx, shri)
1597GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_ZX, vsra_vx, sari)
1598
1599/* Vector Narrowing Integer Right Shift Instructions */
1600static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
1601{
1602    return require_rvv(s) &&
1603           vext_check_isa_ill(s) &&
1604           vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm);
1605}
1606
1607/* OPIVV with NARROW */
1608#define GEN_OPIVV_NARROW_TRANS(NAME)                               \
1609static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1610{                                                                  \
1611    if (opivv_narrow_check(s, a)) {                                \
1612        uint32_t data = 0;                                         \
1613        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1614            gen_helper_##NAME##_b,                                 \
1615            gen_helper_##NAME##_h,                                 \
1616            gen_helper_##NAME##_w,                                 \
1617        };                                                         \
1618        TCGLabel *over = gen_new_label();                          \
1619        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1620                                                                   \
1621        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1622        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1623        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1624                           vreg_ofs(s, a->rs1),                    \
1625                           vreg_ofs(s, a->rs2), cpu_env,           \
1626                           s->vlen / 8, s->vlen / 8, data,         \
1627                           fns[s->sew]);                           \
1628        mark_vs_dirty(s);                                          \
1629        gen_set_label(over);                                       \
1630        return true;                                               \
1631    }                                                              \
1632    return false;                                                  \
1633}
1634GEN_OPIVV_NARROW_TRANS(vnsra_vv)
1635GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
1636
1637static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
1638{
1639    return require_rvv(s) &&
1640           vext_check_isa_ill(s) &&
1641           vext_check_sd(s, a->rd, a->rs2, a->vm);
1642}
1643
1644/* OPIVX with NARROW */
1645#define GEN_OPIVX_NARROW_TRANS(NAME)                                     \
1646static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1647{                                                                        \
1648    if (opivx_narrow_check(s, a)) {                                      \
1649        static gen_helper_opivx * const fns[3] = {                       \
1650            gen_helper_##NAME##_b,                                       \
1651            gen_helper_##NAME##_h,                                       \
1652            gen_helper_##NAME##_w,                                       \
1653        };                                                               \
1654        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1655    }                                                                    \
1656    return false;                                                        \
1657}
1658
1659GEN_OPIVX_NARROW_TRANS(vnsra_vx)
1660GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
1661
1662/* OPIVI with NARROW */
1663#define GEN_OPIVI_NARROW_TRANS(NAME, IMM_MODE, OPIVX)                    \
1664static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1665{                                                                        \
1666    if (opivx_narrow_check(s, a)) {                                      \
1667        static gen_helper_opivx * const fns[3] = {                       \
1668            gen_helper_##OPIVX##_b,                                      \
1669            gen_helper_##OPIVX##_h,                                      \
1670            gen_helper_##OPIVX##_w,                                      \
1671        };                                                               \
1672        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1673                           fns[s->sew], s, IMM_MODE);                    \
1674    }                                                                    \
1675    return false;                                                        \
1676}
1677
1678GEN_OPIVI_NARROW_TRANS(vnsra_vi, IMM_ZX, vnsra_vx)
1679GEN_OPIVI_NARROW_TRANS(vnsrl_vi, IMM_ZX, vnsrl_vx)
1680
1681/* Vector Integer Comparison Instructions */
1682/*
1683 * For all comparison instructions, an illegal instruction exception is raised
1684 * if the destination vector register overlaps a source vector register group
1685 * and LMUL > 1.
1686 */
1687static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1688{
1689    return require_rvv(s) &&
1690           vext_check_isa_ill(s) &&
1691           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1692}
1693
1694GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1695GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1696GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1697GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1698GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1699GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1700
1701static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1702{
1703    return require_rvv(s) &&
1704           vext_check_isa_ill(s) &&
1705           vext_check_ms(s, a->rd, a->rs2);
1706}
1707
1708GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1709GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1710GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1711GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1712GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1713GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1714GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1715GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1716
1717GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check)
1718GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check)
1719GEN_OPIVI_TRANS(vmsleu_vi, IMM_ZX, vmsleu_vx, opivx_cmp_check)
1720GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check)
1721GEN_OPIVI_TRANS(vmsgtu_vi, IMM_ZX, vmsgtu_vx, opivx_cmp_check)
1722GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check)
1723
1724/* Vector Integer Min/Max Instructions */
1725GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1726GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1727GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1728GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1729GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1730GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1731GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1732GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1733
1734/* Vector Single-Width Integer Multiply Instructions */
1735GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1736GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1737GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1738GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1739GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1740GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1741GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1742GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1743
1744/* Vector Integer Divide Instructions */
1745GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1746GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1747GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1748GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1749GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1750GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1751GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1752GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1753
1754/* Vector Widening Integer Multiply Instructions */
1755GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1756GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1757GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1758GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1759GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1760GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1761
1762/* Vector Single-Width Integer Multiply-Add Instructions */
1763GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1764GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1765GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1766GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1767GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1768GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1769GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1770GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1771
1772/* Vector Widening Integer Multiply-Add Instructions */
1773GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1774GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1775GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1776GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1777GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1778GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1779GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1780
1781/* Vector Integer Merge and Move Instructions */
1782static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1783{
1784    if (require_rvv(s) &&
1785        vext_check_isa_ill(s) &&
1786        /* vmv.v.v has rs2 = 0 and vm = 1 */
1787        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
1788        if (s->vl_eq_vlmax) {
1789            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1790                             vreg_ofs(s, a->rs1),
1791                             MAXSZ(s), MAXSZ(s));
1792        } else {
1793            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1794            static gen_helper_gvec_2_ptr * const fns[4] = {
1795                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1796                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1797            };
1798            TCGLabel *over = gen_new_label();
1799            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1800
1801            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1802                               cpu_env, s->vlen / 8, s->vlen / 8, data,
1803                               fns[s->sew]);
1804            gen_set_label(over);
1805        }
1806        mark_vs_dirty(s);
1807        return true;
1808    }
1809    return false;
1810}
1811
1812typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1813static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1814{
1815    if (require_rvv(s) &&
1816        vext_check_isa_ill(s) &&
1817        /* vmv.v.x has rs2 = 0 and vm = 1 */
1818        vext_check_ss(s, a->rd, 0, 1)) {
1819        TCGv s1;
1820        TCGLabel *over = gen_new_label();
1821        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1822
1823        s1 = get_gpr(s, a->rs1, EXT_SIGN);
1824
1825        if (s->vl_eq_vlmax) {
1826            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1827                                MAXSZ(s), MAXSZ(s), s1);
1828        } else {
1829            TCGv_i32 desc;
1830            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1831            TCGv_ptr dest = tcg_temp_new_ptr();
1832            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1833            static gen_helper_vmv_vx * const fns[4] = {
1834                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1835                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1836            };
1837
1838            tcg_gen_ext_tl_i64(s1_i64, s1);
1839            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1840            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1841            fns[s->sew](dest, s1_i64, cpu_env, desc);
1842
1843            tcg_temp_free_ptr(dest);
1844            tcg_temp_free_i64(s1_i64);
1845        }
1846
1847        mark_vs_dirty(s);
1848        gen_set_label(over);
1849        return true;
1850    }
1851    return false;
1852}
1853
1854static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
1855{
1856    if (require_rvv(s) &&
1857        vext_check_isa_ill(s) &&
1858        /* vmv.v.i has rs2 = 0 and vm = 1 */
1859        vext_check_ss(s, a->rd, 0, 1)) {
1860        int64_t simm = sextract64(a->rs1, 0, 5);
1861        if (s->vl_eq_vlmax) {
1862            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
1863                                 MAXSZ(s), MAXSZ(s), simm);
1864            mark_vs_dirty(s);
1865        } else {
1866            TCGv_i32 desc;
1867            TCGv_i64 s1;
1868            TCGv_ptr dest;
1869            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1870            static gen_helper_vmv_vx * const fns[4] = {
1871                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1872                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1873            };
1874            TCGLabel *over = gen_new_label();
1875            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1876
1877            s1 = tcg_constant_i64(simm);
1878            dest = tcg_temp_new_ptr();
1879            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1880            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1881            fns[s->sew](dest, s1, cpu_env, desc);
1882
1883            tcg_temp_free_ptr(dest);
1884            mark_vs_dirty(s);
1885            gen_set_label(over);
1886        }
1887        return true;
1888    }
1889    return false;
1890}
1891
1892GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
1893GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
1894GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
1895
1896/*
1897 *** Vector Fixed-Point Arithmetic Instructions
1898 */
1899
1900/* Vector Single-Width Saturating Add and Subtract */
1901GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
1902GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
1903GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
1904GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
1905GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
1906GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
1907GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
1908GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
1909GEN_OPIVI_TRANS(vsaddu_vi, IMM_ZX, vsaddu_vx, opivx_check)
1910GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
1911
1912/* Vector Single-Width Averaging Add and Subtract */
1913GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
1914GEN_OPIVV_TRANS(vasub_vv, opivv_check)
1915GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
1916GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
1917GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
1918
1919/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1920GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
1921GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
1922
1923/* Vector Widening Saturating Scaled Multiply-Add */
1924GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
1925GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
1926GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
1927GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
1928GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
1929GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
1930GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
1931
1932/* Vector Single-Width Scaling Shift Instructions */
1933GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
1934GEN_OPIVV_TRANS(vssra_vv, opivv_check)
1935GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
1936GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
1937GEN_OPIVI_TRANS(vssrl_vi, IMM_ZX, vssrl_vx, opivx_check)
1938GEN_OPIVI_TRANS(vssra_vi, IMM_SX, vssra_vx, opivx_check)
1939
1940/* Vector Narrowing Fixed-Point Clip Instructions */
1941GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
1942GEN_OPIVV_NARROW_TRANS(vnclip_vv)
1943GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
1944GEN_OPIVX_NARROW_TRANS(vnclip_vx)
1945GEN_OPIVI_NARROW_TRANS(vnclipu_vi, IMM_ZX, vnclipu_vx)
1946GEN_OPIVI_NARROW_TRANS(vnclip_vi, IMM_ZX, vnclip_vx)
1947
1948/*
1949 *** Vector Float Point Arithmetic Instructions
1950 */
1951
1952/*
1953 * As RVF-only cpus always have values NaN-boxed to 64-bits,
1954 * RVF and RVD can be treated equally.
1955 * We don't have to deal with the cases of: SEW > FLEN.
1956 *
1957 * If SEW < FLEN, check whether input fp register is a valid
1958 * NaN-boxed value, in which case the least-significant SEW bits
1959 * of the f regsiter are used, else the canonical NaN value is used.
1960 */
1961static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
1962{
1963    switch (s->sew) {
1964    case 1:
1965        gen_check_nanbox_h(out, in);
1966        break;
1967    case 2:
1968        gen_check_nanbox_s(out, in);
1969        break;
1970    case 3:
1971        tcg_gen_mov_i64(out, in);
1972        break;
1973    default:
1974        g_assert_not_reached();
1975    }
1976}
1977
1978/* Vector Single-Width Floating-Point Add/Subtract Instructions */
1979
1980/*
1981 * If the current SEW does not correspond to a supported IEEE floating-point
1982 * type, an illegal instruction exception is raised.
1983 */
1984static bool opfvv_check(DisasContext *s, arg_rmrr *a)
1985{
1986    return require_rvv(s) &&
1987           require_rvf(s) &&
1988           vext_check_isa_ill(s) &&
1989           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1990}
1991
1992/* OPFVV without GVEC IR */
1993#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
1994static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1995{                                                                  \
1996    if (CHECK(s, a)) {                                             \
1997        uint32_t data = 0;                                         \
1998        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1999            gen_helper_##NAME##_h,                                 \
2000            gen_helper_##NAME##_w,                                 \
2001            gen_helper_##NAME##_d,                                 \
2002        };                                                         \
2003        TCGLabel *over = gen_new_label();                          \
2004        gen_set_rm(s, 7);                                          \
2005        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2006                                                                   \
2007        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2008        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2009        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2010                           vreg_ofs(s, a->rs1),                    \
2011                           vreg_ofs(s, a->rs2), cpu_env,           \
2012                           s->vlen / 8, s->vlen / 8, data,         \
2013                           fns[s->sew - 1]);                       \
2014        mark_vs_dirty(s);                                          \
2015        gen_set_label(over);                                       \
2016        return true;                                               \
2017    }                                                              \
2018    return false;                                                  \
2019}
2020GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2021GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2022
2023typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2024                              TCGv_env, TCGv_i32);
2025
2026static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2027                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2028{
2029    TCGv_ptr dest, src2, mask;
2030    TCGv_i32 desc;
2031    TCGv_i64 t1;
2032
2033    TCGLabel *over = gen_new_label();
2034    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2035
2036    dest = tcg_temp_new_ptr();
2037    mask = tcg_temp_new_ptr();
2038    src2 = tcg_temp_new_ptr();
2039    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2040
2041    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2042    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2043    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2044
2045    /* NaN-box f[rs1] */
2046    t1 = tcg_temp_new_i64();
2047    do_nanbox(s, t1, cpu_fpr[rs1]);
2048
2049    fn(dest, mask, t1, src2, cpu_env, desc);
2050
2051    tcg_temp_free_ptr(dest);
2052    tcg_temp_free_ptr(mask);
2053    tcg_temp_free_ptr(src2);
2054    tcg_temp_free_i64(t1);
2055    mark_vs_dirty(s);
2056    gen_set_label(over);
2057    return true;
2058}
2059
2060/*
2061 * If the current SEW does not correspond to a supported IEEE floating-point
2062 * type, an illegal instruction exception is raised
2063 */
2064static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2065{
2066    return require_rvv(s) &&
2067           require_rvf(s) &&
2068           vext_check_isa_ill(s) &&
2069           vext_check_ss(s, a->rd, a->rs2, a->vm);
2070}
2071
2072/* OPFVF without GVEC IR */
2073#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2074static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2075{                                                                 \
2076    if (CHECK(s, a)) {                                            \
2077        uint32_t data = 0;                                        \
2078        static gen_helper_opfvf *const fns[3] = {                 \
2079            gen_helper_##NAME##_h,                                \
2080            gen_helper_##NAME##_w,                                \
2081            gen_helper_##NAME##_d,                                \
2082        };                                                        \
2083        gen_set_rm(s, 7);                                         \
2084        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2085        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2086        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2087                           fns[s->sew - 1], s);                   \
2088    }                                                             \
2089    return false;                                                 \
2090}
2091
2092GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2093GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2094GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2095
2096/* Vector Widening Floating-Point Add/Subtract Instructions */
2097static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2098{
2099    return require_rvv(s) &&
2100           require_rvf(s) &&
2101           vext_check_isa_ill(s) &&
2102           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2103}
2104
2105/* OPFVV with WIDEN */
2106#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2107static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2108{                                                                \
2109    if (CHECK(s, a)) {                                           \
2110        uint32_t data = 0;                                       \
2111        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2112            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2113        };                                                       \
2114        TCGLabel *over = gen_new_label();                        \
2115        gen_set_rm(s, 7);                                        \
2116        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2117                                                                 \
2118        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2119        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2120        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2121                           vreg_ofs(s, a->rs1),                  \
2122                           vreg_ofs(s, a->rs2), cpu_env,         \
2123                           s->vlen / 8, s->vlen / 8, data,       \
2124                           fns[s->sew - 1]);                     \
2125        mark_vs_dirty(s);                                        \
2126        gen_set_label(over);                                     \
2127        return true;                                             \
2128    }                                                            \
2129    return false;                                                \
2130}
2131
2132GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2133GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2134
2135static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2136{
2137    return require_rvv(s) &&
2138           require_rvf(s) &&
2139           vext_check_isa_ill(s) &&
2140           vext_check_ds(s, a->rd, a->rs2, a->vm);
2141}
2142
2143/* OPFVF with WIDEN */
2144#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2145static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2146{                                                                \
2147    if (opfvf_widen_check(s, a)) {                               \
2148        uint32_t data = 0;                                       \
2149        static gen_helper_opfvf *const fns[2] = {                \
2150            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2151        };                                                       \
2152        gen_set_rm(s, 7);                                        \
2153        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2154        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2155        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2156                           fns[s->sew - 1], s);                  \
2157    }                                                            \
2158    return false;                                                \
2159}
2160
2161GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2162GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2163
2164static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2165{
2166    return require_rvv(s) &&
2167           require_rvf(s) &&
2168           vext_check_isa_ill(s) &&
2169           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2170}
2171
2172/* WIDEN OPFVV with WIDEN */
2173#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2174static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2175{                                                                  \
2176    if (opfwv_widen_check(s, a)) {                                 \
2177        uint32_t data = 0;                                         \
2178        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2179            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2180        };                                                         \
2181        TCGLabel *over = gen_new_label();                          \
2182        gen_set_rm(s, 7);                                          \
2183        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2184                                                                   \
2185        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2186        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2187        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2188                           vreg_ofs(s, a->rs1),                    \
2189                           vreg_ofs(s, a->rs2), cpu_env,           \
2190                           s->vlen / 8, s->vlen / 8, data,         \
2191                           fns[s->sew - 1]);                       \
2192        mark_vs_dirty(s);                                          \
2193        gen_set_label(over);                                       \
2194        return true;                                               \
2195    }                                                              \
2196    return false;                                                  \
2197}
2198
2199GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2200GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2201
2202static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2203{
2204    return require_rvv(s) &&
2205           require_rvf(s) &&
2206           vext_check_isa_ill(s) &&
2207           vext_check_dd(s, a->rd, a->rs2, a->vm);
2208}
2209
2210/* WIDEN OPFVF with WIDEN */
2211#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2212static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2213{                                                                \
2214    if (opfwf_widen_check(s, a)) {                               \
2215        uint32_t data = 0;                                       \
2216        static gen_helper_opfvf *const fns[2] = {                \
2217            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2218        };                                                       \
2219        gen_set_rm(s, 7);                                        \
2220        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2221        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2222        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2223                           fns[s->sew - 1], s);                  \
2224    }                                                            \
2225    return false;                                                \
2226}
2227
2228GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2229GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2230
2231/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2232GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2233GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2234GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2235GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2236GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2237
2238/* Vector Widening Floating-Point Multiply */
2239GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2240GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2241
2242/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2243GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2244GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2245GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2246GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2247GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2248GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2249GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2250GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2251GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2252GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2253GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2254GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2255GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2256GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2257GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2258GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2259
2260/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2261GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2262GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2263GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2264GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2265GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2266GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2267GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2268GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2269
2270/* Vector Floating-Point Square-Root Instruction */
2271
2272/*
2273 * If the current SEW does not correspond to a supported IEEE floating-point
2274 * type, an illegal instruction exception is raised
2275 */
2276static bool opfv_check(DisasContext *s, arg_rmr *a)
2277{
2278    return require_rvv(s) &&
2279           require_rvf(s) &&
2280           vext_check_isa_ill(s) &&
2281           /* OPFV instructions ignore vs1 check */
2282           vext_check_ss(s, a->rd, a->rs2, a->vm);
2283}
2284
2285#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2286static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2287{                                                                  \
2288    if (CHECK(s, a)) {                                             \
2289        uint32_t data = 0;                                         \
2290        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2291            gen_helper_##NAME##_h,                                 \
2292            gen_helper_##NAME##_w,                                 \
2293            gen_helper_##NAME##_d,                                 \
2294        };                                                         \
2295        TCGLabel *over = gen_new_label();                          \
2296        gen_set_rm(s, 7);                                          \
2297        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2298                                                                   \
2299        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2300        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2301        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2302                           vreg_ofs(s, a->rs2), cpu_env,           \
2303                           s->vlen / 8, s->vlen / 8, data,         \
2304                           fns[s->sew - 1]);                       \
2305        mark_vs_dirty(s);                                          \
2306        gen_set_label(over);                                       \
2307        return true;                                               \
2308    }                                                              \
2309    return false;                                                  \
2310}
2311
2312GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2313
2314/* Vector Floating-Point MIN/MAX Instructions */
2315GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2316GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2317GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2318GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2319
2320/* Vector Floating-Point Sign-Injection Instructions */
2321GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2322GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2323GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2324GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2325GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2326GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2327
2328/* Vector Floating-Point Compare Instructions */
2329static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2330{
2331    return require_rvv(s) &&
2332           require_rvf(s) &&
2333           vext_check_isa_ill(s) &&
2334           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2335}
2336
2337GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2338GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2339GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2340GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2341GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2342
2343static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2344{
2345    return require_rvv(s) &&
2346           require_rvf(s) &&
2347           vext_check_isa_ill(s) &&
2348           vext_check_ms(s, a->rd, a->rs2);
2349}
2350
2351GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2352GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2353GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2354GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2355GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2356GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2357GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2358
2359/* Vector Floating-Point Classify Instruction */
2360GEN_OPFV_TRANS(vfclass_v, opfv_check)
2361
2362/* Vector Floating-Point Merge Instruction */
2363GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2364
2365static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2366{
2367    if (require_rvv(s) &&
2368        require_rvf(s) &&
2369        vext_check_isa_ill(s) &&
2370        require_align(a->rd, s->lmul)) {
2371        if (s->vl_eq_vlmax) {
2372            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2373                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2374            mark_vs_dirty(s);
2375        } else {
2376            TCGv_ptr dest;
2377            TCGv_i32 desc;
2378            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2379            static gen_helper_vmv_vx * const fns[3] = {
2380                gen_helper_vmv_v_x_h,
2381                gen_helper_vmv_v_x_w,
2382                gen_helper_vmv_v_x_d,
2383            };
2384            TCGLabel *over = gen_new_label();
2385            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2386
2387            dest = tcg_temp_new_ptr();
2388            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2389            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2390            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2391
2392            tcg_temp_free_ptr(dest);
2393            mark_vs_dirty(s);
2394            gen_set_label(over);
2395        }
2396        return true;
2397    }
2398    return false;
2399}
2400
2401/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2402GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2403GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2404GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2405GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2406
2407/* Widening Floating-Point/Integer Type-Convert Instructions */
2408
2409/*
2410 * If the current SEW does not correspond to a supported IEEE floating-point
2411 * type, an illegal instruction exception is raised
2412 */
2413static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2414{
2415    return require_rvv(s) &&
2416           require_scale_rvf(s) &&
2417           (s->sew != MO_8) &&
2418           vext_check_isa_ill(s) &&
2419           vext_check_ds(s, a->rd, a->rs2, a->vm);
2420}
2421
2422#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2423static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2424{                                                                  \
2425    if (opfv_widen_check(s, a)) {                                  \
2426        uint32_t data = 0;                                         \
2427        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2428            gen_helper_##NAME##_h,                                 \
2429            gen_helper_##NAME##_w,                                 \
2430        };                                                         \
2431        TCGLabel *over = gen_new_label();                          \
2432        gen_set_rm(s, 7);                                          \
2433        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2434                                                                   \
2435        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2436        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2437        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2438                           vreg_ofs(s, a->rs2), cpu_env,           \
2439                           s->vlen / 8, s->vlen / 8, data,         \
2440                           fns[s->sew - 1]);                       \
2441        mark_vs_dirty(s);                                          \
2442        gen_set_label(over);                                       \
2443        return true;                                               \
2444    }                                                              \
2445    return false;                                                  \
2446}
2447
2448GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2449GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2450GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2451GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2452GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2453
2454/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2455
2456/*
2457 * If the current SEW does not correspond to a supported IEEE floating-point
2458 * type, an illegal instruction exception is raised
2459 */
2460static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2461{
2462    return require_rvv(s) &&
2463           require_rvf(s) &&
2464           (s->sew != MO_64) &&
2465           vext_check_isa_ill(s) &&
2466           /* OPFV narrowing instructions ignore vs1 check */
2467           vext_check_sd(s, a->rd, a->rs2, a->vm);
2468}
2469
2470#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2471static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2472{                                                                  \
2473    if (opfv_narrow_check(s, a)) {                                 \
2474        uint32_t data = 0;                                         \
2475        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2476            gen_helper_##NAME##_h,                                 \
2477            gen_helper_##NAME##_w,                                 \
2478        };                                                         \
2479        TCGLabel *over = gen_new_label();                          \
2480        gen_set_rm(s, 7);                                          \
2481        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2482                                                                   \
2483        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2484        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2485        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2486                           vreg_ofs(s, a->rs2), cpu_env,           \
2487                           s->vlen / 8, s->vlen / 8, data,         \
2488                           fns[s->sew - 1]);                       \
2489        mark_vs_dirty(s);                                          \
2490        gen_set_label(over);                                       \
2491        return true;                                               \
2492    }                                                              \
2493    return false;                                                  \
2494}
2495
2496GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2497GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2498GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2499GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2500GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2501
2502/*
2503 *** Vector Reduction Operations
2504 */
2505/* Vector Single-Width Integer Reduction Instructions */
2506static bool reduction_check(DisasContext *s, arg_rmrr *a)
2507{
2508    return require_rvv(s) &&
2509           vext_check_isa_ill(s) &&
2510           vext_check_reduction(s, a->rs2);
2511}
2512
2513GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2514GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2515GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2516GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2517GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2518GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2519GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2520GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2521
2522/* Vector Widening Integer Reduction Instructions */
2523static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
2524{
2525    return reduction_check(s, a) && (s->sew < MO_64);
2526}
2527
2528GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
2529GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
2530
2531/* Vector Single-Width Floating-Point Reduction Instructions */
2532GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2533GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2534GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2535
2536/* Vector Widening Floating-Point Reduction Instructions */
2537GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2538
2539/*
2540 *** Vector Mask Operations
2541 */
2542
2543/* Vector Mask-Register Logical Instructions */
2544#define GEN_MM_TRANS(NAME)                                         \
2545static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2546{                                                                  \
2547    if (vext_check_isa_ill(s)) {                                   \
2548        uint32_t data = 0;                                         \
2549        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2550        TCGLabel *over = gen_new_label();                          \
2551        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2552                                                                   \
2553        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2554        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2555                           vreg_ofs(s, a->rs1),                    \
2556                           vreg_ofs(s, a->rs2), cpu_env,           \
2557                           s->vlen / 8, s->vlen / 8, data, fn);    \
2558        mark_vs_dirty(s);                                          \
2559        gen_set_label(over);                                       \
2560        return true;                                               \
2561    }                                                              \
2562    return false;                                                  \
2563}
2564
2565GEN_MM_TRANS(vmand_mm)
2566GEN_MM_TRANS(vmnand_mm)
2567GEN_MM_TRANS(vmandnot_mm)
2568GEN_MM_TRANS(vmxor_mm)
2569GEN_MM_TRANS(vmor_mm)
2570GEN_MM_TRANS(vmnor_mm)
2571GEN_MM_TRANS(vmornot_mm)
2572GEN_MM_TRANS(vmxnor_mm)
2573
2574/* Vector mask population count vmpopc */
2575static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2576{
2577    if (require_rvv(s) &&
2578        vext_check_isa_ill(s)) {
2579        TCGv_ptr src2, mask;
2580        TCGv dst;
2581        TCGv_i32 desc;
2582        uint32_t data = 0;
2583        data = FIELD_DP32(data, VDATA, VM, a->vm);
2584        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2585
2586        mask = tcg_temp_new_ptr();
2587        src2 = tcg_temp_new_ptr();
2588        dst = dest_gpr(s, a->rd);
2589        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2590
2591        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2592        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2593
2594        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2595        gen_set_gpr(s, a->rd, dst);
2596
2597        tcg_temp_free_ptr(mask);
2598        tcg_temp_free_ptr(src2);
2599        return true;
2600    }
2601    return false;
2602}
2603
2604/* vmfirst find-first-set mask bit */
2605static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2606{
2607    if (require_rvv(s) &&
2608        vext_check_isa_ill(s)) {
2609        TCGv_ptr src2, mask;
2610        TCGv dst;
2611        TCGv_i32 desc;
2612        uint32_t data = 0;
2613        data = FIELD_DP32(data, VDATA, VM, a->vm);
2614        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2615
2616        mask = tcg_temp_new_ptr();
2617        src2 = tcg_temp_new_ptr();
2618        dst = dest_gpr(s, a->rd);
2619        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2620
2621        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2622        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2623
2624        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2625        gen_set_gpr(s, a->rd, dst);
2626
2627        tcg_temp_free_ptr(mask);
2628        tcg_temp_free_ptr(src2);
2629        return true;
2630    }
2631    return false;
2632}
2633
2634/* vmsbf.m set-before-first mask bit */
2635/* vmsif.m set-includ-first mask bit */
2636/* vmsof.m set-only-first mask bit */
2637#define GEN_M_TRANS(NAME)                                          \
2638static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2639{                                                                  \
2640    if (vext_check_isa_ill(s)) {                                   \
2641        uint32_t data = 0;                                         \
2642        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2643        TCGLabel *over = gen_new_label();                          \
2644        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2645                                                                   \
2646        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2647        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2648        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2649                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2650                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2651                           data, fn);                              \
2652        mark_vs_dirty(s);                                          \
2653        gen_set_label(over);                                       \
2654        return true;                                               \
2655    }                                                              \
2656    return false;                                                  \
2657}
2658
2659GEN_M_TRANS(vmsbf_m)
2660GEN_M_TRANS(vmsif_m)
2661GEN_M_TRANS(vmsof_m)
2662
2663/* Vector Iota Instruction */
2664static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2665{
2666    if (require_rvv(s) &&
2667        vext_check_isa_ill(s) &&
2668        require_noover(a->rd, s->lmul, a->rs2, 0) &&
2669        require_vm(a->vm, a->rd) &&
2670        require_align(a->rd, s->lmul)) {
2671        uint32_t data = 0;
2672        TCGLabel *over = gen_new_label();
2673        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2674
2675        data = FIELD_DP32(data, VDATA, VM, a->vm);
2676        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2677        static gen_helper_gvec_3_ptr * const fns[4] = {
2678            gen_helper_viota_m_b, gen_helper_viota_m_h,
2679            gen_helper_viota_m_w, gen_helper_viota_m_d,
2680        };
2681        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2682                           vreg_ofs(s, a->rs2), cpu_env,
2683                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2684        mark_vs_dirty(s);
2685        gen_set_label(over);
2686        return true;
2687    }
2688    return false;
2689}
2690
2691/* Vector Element Index Instruction */
2692static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2693{
2694    if (require_rvv(s) &&
2695        vext_check_isa_ill(s) &&
2696        require_align(a->rd, s->lmul) &&
2697        require_vm(a->vm, a->rd)) {
2698        uint32_t data = 0;
2699        TCGLabel *over = gen_new_label();
2700        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2701
2702        data = FIELD_DP32(data, VDATA, VM, a->vm);
2703        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2704        static gen_helper_gvec_2_ptr * const fns[4] = {
2705            gen_helper_vid_v_b, gen_helper_vid_v_h,
2706            gen_helper_vid_v_w, gen_helper_vid_v_d,
2707        };
2708        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2709                           cpu_env, s->vlen / 8, s->vlen / 8,
2710                           data, fns[s->sew]);
2711        mark_vs_dirty(s);
2712        gen_set_label(over);
2713        return true;
2714    }
2715    return false;
2716}
2717
2718/*
2719 *** Vector Permutation Instructions
2720 */
2721
2722/* Integer Extract Instruction */
2723
2724static void load_element(TCGv_i64 dest, TCGv_ptr base,
2725                         int ofs, int sew)
2726{
2727    switch (sew) {
2728    case MO_8:
2729        tcg_gen_ld8u_i64(dest, base, ofs);
2730        break;
2731    case MO_16:
2732        tcg_gen_ld16u_i64(dest, base, ofs);
2733        break;
2734    case MO_32:
2735        tcg_gen_ld32u_i64(dest, base, ofs);
2736        break;
2737    case MO_64:
2738        tcg_gen_ld_i64(dest, base, ofs);
2739        break;
2740    default:
2741        g_assert_not_reached();
2742        break;
2743    }
2744}
2745
2746/* offset of the idx element with base regsiter r */
2747static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2748{
2749#ifdef HOST_WORDS_BIGENDIAN
2750    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2751#else
2752    return vreg_ofs(s, r) + (idx << s->sew);
2753#endif
2754}
2755
2756/* adjust the index according to the endian */
2757static void endian_adjust(TCGv_i32 ofs, int sew)
2758{
2759#ifdef HOST_WORDS_BIGENDIAN
2760    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2761#endif
2762}
2763
2764/* Load idx >= VLMAX ? 0 : vreg[idx] */
2765static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2766                              int vreg, TCGv idx, int vlmax)
2767{
2768    TCGv_i32 ofs = tcg_temp_new_i32();
2769    TCGv_ptr base = tcg_temp_new_ptr();
2770    TCGv_i64 t_idx = tcg_temp_new_i64();
2771    TCGv_i64 t_vlmax, t_zero;
2772
2773    /*
2774     * Mask the index to the length so that we do
2775     * not produce an out-of-range load.
2776     */
2777    tcg_gen_trunc_tl_i32(ofs, idx);
2778    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2779
2780    /* Convert the index to an offset. */
2781    endian_adjust(ofs, s->sew);
2782    tcg_gen_shli_i32(ofs, ofs, s->sew);
2783
2784    /* Convert the index to a pointer. */
2785    tcg_gen_ext_i32_ptr(base, ofs);
2786    tcg_gen_add_ptr(base, base, cpu_env);
2787
2788    /* Perform the load. */
2789    load_element(dest, base,
2790                 vreg_ofs(s, vreg), s->sew);
2791    tcg_temp_free_ptr(base);
2792    tcg_temp_free_i32(ofs);
2793
2794    /* Flush out-of-range indexing to zero.  */
2795    t_vlmax = tcg_constant_i64(vlmax);
2796    t_zero = tcg_constant_i64(0);
2797    tcg_gen_extu_tl_i64(t_idx, idx);
2798
2799    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2800                        t_vlmax, dest, t_zero);
2801
2802    tcg_temp_free_i64(t_idx);
2803}
2804
2805static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2806                              int vreg, int idx)
2807{
2808    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2809}
2810
2811static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2812{
2813    TCGv_i64 tmp = tcg_temp_new_i64();
2814    TCGv dest = dest_gpr(s, a->rd);
2815
2816    if (a->rs1 == 0) {
2817        /* Special case vmv.x.s rd, vs2. */
2818        vec_element_loadi(s, tmp, a->rs2, 0);
2819    } else {
2820        /* This instruction ignores LMUL and vector register groups */
2821        int vlmax = s->vlen >> (3 + s->sew);
2822        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2823    }
2824
2825    tcg_gen_trunc_i64_tl(dest, tmp);
2826    gen_set_gpr(s, a->rd, dest);
2827
2828    tcg_temp_free_i64(tmp);
2829    return true;
2830}
2831
2832/* Integer Scalar Move Instruction */
2833
2834static void store_element(TCGv_i64 val, TCGv_ptr base,
2835                          int ofs, int sew)
2836{
2837    switch (sew) {
2838    case MO_8:
2839        tcg_gen_st8_i64(val, base, ofs);
2840        break;
2841    case MO_16:
2842        tcg_gen_st16_i64(val, base, ofs);
2843        break;
2844    case MO_32:
2845        tcg_gen_st32_i64(val, base, ofs);
2846        break;
2847    case MO_64:
2848        tcg_gen_st_i64(val, base, ofs);
2849        break;
2850    default:
2851        g_assert_not_reached();
2852        break;
2853    }
2854}
2855
2856/*
2857 * Store vreg[idx] = val.
2858 * The index must be in range of VLMAX.
2859 */
2860static void vec_element_storei(DisasContext *s, int vreg,
2861                               int idx, TCGv_i64 val)
2862{
2863    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2864}
2865
2866/* vmv.s.x vd, rs1 # vd[0] = rs1 */
2867static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
2868{
2869    if (vext_check_isa_ill(s)) {
2870        /* This instruction ignores LMUL and vector register groups */
2871        int maxsz = s->vlen >> 3;
2872        TCGv_i64 t1;
2873        TCGLabel *over = gen_new_label();
2874
2875        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2876        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
2877        if (a->rs1 == 0) {
2878            goto done;
2879        }
2880
2881        t1 = tcg_temp_new_i64();
2882        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
2883        vec_element_storei(s, a->rd, 0, t1);
2884        tcg_temp_free_i64(t1);
2885        mark_vs_dirty(s);
2886    done:
2887        gen_set_label(over);
2888        return true;
2889    }
2890    return false;
2891}
2892
2893/* Floating-Point Scalar Move Instructions */
2894static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
2895{
2896    if (!s->vill && has_ext(s, RVF) &&
2897        (s->mstatus_fs != 0) && (s->sew != 0)) {
2898        unsigned int len = 8 << s->sew;
2899
2900        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
2901        if (len < 64) {
2902            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
2903                            MAKE_64BIT_MASK(len, 64 - len));
2904        }
2905
2906        mark_fs_dirty(s);
2907        return true;
2908    }
2909    return false;
2910}
2911
2912/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2913static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
2914{
2915    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
2916        TCGv_i64 t1;
2917        /* The instructions ignore LMUL and vector register group. */
2918        uint32_t vlmax = s->vlen >> 3;
2919
2920        /* if vl == 0, skip vector register write back */
2921        TCGLabel *over = gen_new_label();
2922        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2923
2924        /* zeroed all elements */
2925        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
2926
2927        /* NaN-box f[rs1] as necessary for SEW */
2928        t1 = tcg_temp_new_i64();
2929        if (s->sew == MO_64 && !has_ext(s, RVD)) {
2930            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
2931        } else {
2932            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
2933        }
2934        vec_element_storei(s, a->rd, 0, t1);
2935        tcg_temp_free_i64(t1);
2936        mark_vs_dirty(s);
2937        gen_set_label(over);
2938        return true;
2939    }
2940    return false;
2941}
2942
2943/* Vector Slide Instructions */
2944static bool slideup_check(DisasContext *s, arg_rmrr *a)
2945{
2946    return require_rvv(s) &&
2947           vext_check_isa_ill(s) &&
2948           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
2949}
2950
2951GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
2952GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
2953GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
2954
2955static bool slidedown_check(DisasContext *s, arg_rmrr *a)
2956{
2957    return require_rvv(s) &&
2958           vext_check_isa_ill(s) &&
2959           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
2960}
2961
2962GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
2963GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
2964GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
2965
2966/* Vector Register Gather Instruction */
2967static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
2968{
2969    return require_rvv(s) &&
2970           vext_check_isa_ill(s) &&
2971           require_align(a->rd, s->lmul) &&
2972           require_align(a->rs1, s->lmul) &&
2973           require_align(a->rs2, s->lmul) &&
2974           (a->rd != a->rs2 && a->rd != a->rs1) &&
2975           require_vm(a->vm, a->rd);
2976}
2977
2978GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
2979
2980static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
2981{
2982    return require_rvv(s) &&
2983           vext_check_isa_ill(s) &&
2984           require_align(a->rd, s->lmul) &&
2985           require_align(a->rs2, s->lmul) &&
2986           (a->rd != a->rs2) &&
2987           require_vm(a->vm, a->rd);
2988}
2989
2990/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
2991static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
2992{
2993    if (!vrgather_vx_check(s, a)) {
2994        return false;
2995    }
2996
2997    if (a->vm && s->vl_eq_vlmax) {
2998        int vlmax = s->vlen;
2999        TCGv_i64 dest = tcg_temp_new_i64();
3000
3001        if (a->rs1 == 0) {
3002            vec_element_loadi(s, dest, a->rs2, 0);
3003        } else {
3004            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3005        }
3006
3007        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3008                             MAXSZ(s), MAXSZ(s), dest);
3009        tcg_temp_free_i64(dest);
3010        mark_vs_dirty(s);
3011    } else {
3012        static gen_helper_opivx * const fns[4] = {
3013            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3014            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3015        };
3016        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3017    }
3018    return true;
3019}
3020
3021/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3022static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3023{
3024    if (!vrgather_vx_check(s, a)) {
3025        return false;
3026    }
3027
3028    if (a->vm && s->vl_eq_vlmax) {
3029        if (a->rs1 >= s->vlen) {
3030            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
3031                                 MAXSZ(s), MAXSZ(s), 0);
3032        } else {
3033            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3034                                 endian_ofs(s, a->rs2, a->rs1),
3035                                 MAXSZ(s), MAXSZ(s));
3036        }
3037        mark_vs_dirty(s);
3038    } else {
3039        static gen_helper_opivx * const fns[4] = {
3040            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3041            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3042        };
3043        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3044                           s, IMM_ZX);
3045    }
3046    return true;
3047}
3048
3049/*
3050 * Vector Compress Instruction
3051 *
3052 * The destination vector register group cannot overlap the
3053 * source vector register group or the source mask register.
3054 */
3055static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3056{
3057    return require_rvv(s) &&
3058           vext_check_isa_ill(s) &&
3059           require_align(a->rd, s->lmul) &&
3060           require_align(a->rs2, s->lmul) &&
3061           (a->rd != a->rs2) &&
3062           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1);
3063}
3064
3065static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3066{
3067    if (vcompress_vm_check(s, a)) {
3068        uint32_t data = 0;
3069        static gen_helper_gvec_4_ptr * const fns[4] = {
3070            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3071            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3072        };
3073        TCGLabel *over = gen_new_label();
3074        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3075
3076        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3077        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3078                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3079                           cpu_env, s->vlen / 8, s->vlen / 8, data,
3080                           fns[s->sew]);
3081        mark_vs_dirty(s);
3082        gen_set_label(over);
3083        return true;
3084    }
3085    return false;
3086}
3087