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 eew)
807{
808    uint32_t data = 0;
809    gen_helper_ldst_index *fn;
810    static gen_helper_ldst_index * const fns[4][4] = {
811        /*
812         * offset vector register group EEW = 8,
813         * data vector register group EEW = SEW
814         */
815        { gen_helper_vlxei8_8_v,  gen_helper_vlxei8_16_v,
816          gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v },
817        /*
818         * offset vector register group EEW = 16,
819         * data vector register group EEW = SEW
820         */
821        { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v,
822          gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v },
823        /*
824         * offset vector register group EEW = 32,
825         * data vector register group EEW = SEW
826         */
827        { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v,
828          gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v },
829        /*
830         * offset vector register group EEW = 64,
831         * data vector register group EEW = SEW
832         */
833        { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v,
834          gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v }
835    };
836
837    fn = fns[eew][s->sew];
838
839    data = FIELD_DP32(data, VDATA, VM, a->vm);
840    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
841    data = FIELD_DP32(data, VDATA, NF, a->nf);
842    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
843}
844
845static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
846{
847    return require_rvv(s) &&
848           vext_check_isa_ill(s) &&
849           vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew);
850}
851
852GEN_VEXT_TRANS(vlxei8_v,  MO_8,  rnfvm, ld_index_op, ld_index_check)
853GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check)
854GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check)
855GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check)
856
857static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew)
858{
859    uint32_t data = 0;
860    gen_helper_ldst_index *fn;
861    static gen_helper_ldst_index * const fns[4][4] = {
862        /*
863         * offset vector register group EEW = 8,
864         * data vector register group EEW = SEW
865         */
866        { gen_helper_vsxei8_8_v,  gen_helper_vsxei8_16_v,
867          gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v },
868        /*
869         * offset vector register group EEW = 16,
870         * data vector register group EEW = SEW
871         */
872        { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v,
873          gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v },
874        /*
875         * offset vector register group EEW = 32,
876         * data vector register group EEW = SEW
877         */
878        { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v,
879          gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v },
880        /*
881         * offset vector register group EEW = 64,
882         * data vector register group EEW = SEW
883         */
884        { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v,
885          gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v }
886    };
887
888    fn = fns[eew][s->sew];
889
890    data = FIELD_DP32(data, VDATA, VM, a->vm);
891    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
892    data = FIELD_DP32(data, VDATA, NF, a->nf);
893    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
894}
895
896static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew)
897{
898    return require_rvv(s) &&
899           vext_check_isa_ill(s) &&
900           vext_check_st_index(s, a->rd, a->rs2, a->nf, eew);
901}
902
903GEN_VEXT_TRANS(vsxei8_v,  MO_8,  rnfvm, st_index_op, st_index_check)
904GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check)
905GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check)
906GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check)
907
908/*
909 *** unit stride fault-only-first load
910 */
911static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
912                       gen_helper_ldst_us *fn, DisasContext *s)
913{
914    TCGv_ptr dest, mask;
915    TCGv base;
916    TCGv_i32 desc;
917
918    TCGLabel *over = gen_new_label();
919    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
920
921    dest = tcg_temp_new_ptr();
922    mask = tcg_temp_new_ptr();
923    base = get_gpr(s, rs1, EXT_NONE);
924    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
925
926    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
927    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
928
929    fn(dest, mask, base, cpu_env, desc);
930
931    tcg_temp_free_ptr(dest);
932    tcg_temp_free_ptr(mask);
933    mark_vs_dirty(s);
934    gen_set_label(over);
935    return true;
936}
937
938static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew)
939{
940    uint32_t data = 0;
941    gen_helper_ldst_us *fn;
942    static gen_helper_ldst_us * const fns[4] = {
943        gen_helper_vle8ff_v, gen_helper_vle16ff_v,
944        gen_helper_vle32ff_v, gen_helper_vle64ff_v
945    };
946
947    fn = fns[eew];
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(vle8ff_v,  MO_8,  r2nfvm, ldff_op, ld_us_check)
959GEN_VEXT_TRANS(vle16ff_v, MO_16, r2nfvm, ldff_op, ld_us_check)
960GEN_VEXT_TRANS(vle32ff_v, MO_32, r2nfvm, ldff_op, ld_us_check)
961GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check)
962
963/*
964 * load and store whole register instructions
965 */
966typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32);
967
968static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf,
969                             gen_helper_ldst_whole *fn, DisasContext *s,
970                             bool is_store)
971{
972    TCGv_ptr dest;
973    TCGv base;
974    TCGv_i32 desc;
975
976    uint32_t data = FIELD_DP32(0, VDATA, NF, nf);
977    dest = tcg_temp_new_ptr();
978    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
979
980    base = get_gpr(s, rs1, EXT_NONE);
981    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
982
983    fn(dest, base, cpu_env, desc);
984
985    tcg_temp_free_ptr(dest);
986
987    if (!is_store) {
988        mark_vs_dirty(s);
989    }
990
991    return true;
992}
993
994/*
995 * load and store whole register instructions ignore vtype and vl setting.
996 * Thus, we don't need to check vill bit. (Section 7.9)
997 */
998#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, IS_STORE)                      \
999static bool trans_##NAME(DisasContext *s, arg_##NAME * a)                 \
1000{                                                                         \
1001    if (require_rvv(s) &&                                                 \
1002        QEMU_IS_ALIGNED(a->rd, ARG_NF)) {                                 \
1003        return ldst_whole_trans(a->rd, a->rs1, ARG_NF, gen_helper_##NAME, \
1004                                s, IS_STORE);                             \
1005    }                                                                     \
1006    return false;                                                         \
1007}
1008
1009GEN_LDST_WHOLE_TRANS(vl1re8_v,  1, false)
1010GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, false)
1011GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, false)
1012GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, false)
1013GEN_LDST_WHOLE_TRANS(vl2re8_v,  2, false)
1014GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, false)
1015GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, false)
1016GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, false)
1017GEN_LDST_WHOLE_TRANS(vl4re8_v,  4, false)
1018GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, false)
1019GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, false)
1020GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, false)
1021GEN_LDST_WHOLE_TRANS(vl8re8_v,  8, false)
1022GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, false)
1023GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, false)
1024GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, false)
1025
1026GEN_LDST_WHOLE_TRANS(vs1r_v, 1, true)
1027GEN_LDST_WHOLE_TRANS(vs2r_v, 2, true)
1028GEN_LDST_WHOLE_TRANS(vs4r_v, 4, true)
1029GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true)
1030
1031/*
1032 *** Vector Integer Arithmetic Instructions
1033 */
1034#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
1035
1036static bool opivv_check(DisasContext *s, arg_rmrr *a)
1037{
1038    return require_rvv(s) &&
1039           vext_check_isa_ill(s) &&
1040           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1041}
1042
1043typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
1044                        uint32_t, uint32_t, uint32_t);
1045
1046static inline bool
1047do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
1048              gen_helper_gvec_4_ptr *fn)
1049{
1050    TCGLabel *over = gen_new_label();
1051    if (!opivv_check(s, a)) {
1052        return false;
1053    }
1054
1055    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1056
1057    if (a->vm && s->vl_eq_vlmax) {
1058        gvec_fn(s->sew, vreg_ofs(s, a->rd),
1059                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
1060                MAXSZ(s), MAXSZ(s));
1061    } else {
1062        uint32_t data = 0;
1063
1064        data = FIELD_DP32(data, VDATA, VM, a->vm);
1065        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1066        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1067                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
1068                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1069    }
1070    mark_vs_dirty(s);
1071    gen_set_label(over);
1072    return true;
1073}
1074
1075/* OPIVV with GVEC IR */
1076#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
1077static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1078{                                                                  \
1079    static gen_helper_gvec_4_ptr * const fns[4] = {                \
1080        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1081        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1082    };                                                             \
1083    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1084}
1085
1086GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
1087GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
1088
1089typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
1090                              TCGv_env, TCGv_i32);
1091
1092static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
1093                        gen_helper_opivx *fn, DisasContext *s)
1094{
1095    TCGv_ptr dest, src2, mask;
1096    TCGv src1;
1097    TCGv_i32 desc;
1098    uint32_t data = 0;
1099
1100    TCGLabel *over = gen_new_label();
1101    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1102
1103    dest = tcg_temp_new_ptr();
1104    mask = tcg_temp_new_ptr();
1105    src2 = tcg_temp_new_ptr();
1106    src1 = get_gpr(s, rs1, EXT_NONE);
1107
1108    data = FIELD_DP32(data, VDATA, VM, vm);
1109    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1110    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1111
1112    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1113    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1114    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1115
1116    fn(dest, mask, src1, src2, cpu_env, desc);
1117
1118    tcg_temp_free_ptr(dest);
1119    tcg_temp_free_ptr(mask);
1120    tcg_temp_free_ptr(src2);
1121    mark_vs_dirty(s);
1122    gen_set_label(over);
1123    return true;
1124}
1125
1126static bool opivx_check(DisasContext *s, arg_rmrr *a)
1127{
1128    return require_rvv(s) &&
1129           vext_check_isa_ill(s) &&
1130           vext_check_ss(s, a->rd, a->rs2, a->vm);
1131}
1132
1133typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
1134                         uint32_t, uint32_t);
1135
1136static inline bool
1137do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
1138              gen_helper_opivx *fn)
1139{
1140    if (!opivx_check(s, a)) {
1141        return false;
1142    }
1143
1144    if (a->vm && s->vl_eq_vlmax) {
1145        TCGv_i64 src1 = tcg_temp_new_i64();
1146
1147        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
1148        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1149                src1, MAXSZ(s), MAXSZ(s));
1150
1151        tcg_temp_free_i64(src1);
1152        mark_vs_dirty(s);
1153        return true;
1154    }
1155    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1156}
1157
1158/* OPIVX with GVEC IR */
1159#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
1160static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1161{                                                                  \
1162    static gen_helper_opivx * const fns[4] = {                     \
1163        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1164        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1165    };                                                             \
1166    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1167}
1168
1169GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
1170GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
1171
1172static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1173{
1174    tcg_gen_vec_sub8_i64(d, b, a);
1175}
1176
1177static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1178{
1179    tcg_gen_vec_sub16_i64(d, b, a);
1180}
1181
1182static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1183{
1184    tcg_gen_sub_i32(ret, arg2, arg1);
1185}
1186
1187static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1188{
1189    tcg_gen_sub_i64(ret, arg2, arg1);
1190}
1191
1192static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
1193{
1194    tcg_gen_sub_vec(vece, r, b, a);
1195}
1196
1197static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
1198                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
1199{
1200    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
1201    static const GVecGen2s rsub_op[4] = {
1202        { .fni8 = gen_vec_rsub8_i64,
1203          .fniv = gen_rsub_vec,
1204          .fno = gen_helper_vec_rsubs8,
1205          .opt_opc = vecop_list,
1206          .vece = MO_8 },
1207        { .fni8 = gen_vec_rsub16_i64,
1208          .fniv = gen_rsub_vec,
1209          .fno = gen_helper_vec_rsubs16,
1210          .opt_opc = vecop_list,
1211          .vece = MO_16 },
1212        { .fni4 = gen_rsub_i32,
1213          .fniv = gen_rsub_vec,
1214          .fno = gen_helper_vec_rsubs32,
1215          .opt_opc = vecop_list,
1216          .vece = MO_32 },
1217        { .fni8 = gen_rsub_i64,
1218          .fniv = gen_rsub_vec,
1219          .fno = gen_helper_vec_rsubs64,
1220          .opt_opc = vecop_list,
1221          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
1222          .vece = MO_64 },
1223    };
1224
1225    tcg_debug_assert(vece <= MO_64);
1226    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
1227}
1228
1229GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1230
1231typedef enum {
1232    IMM_ZX,         /* Zero-extended */
1233    IMM_SX,         /* Sign-extended */
1234    IMM_TRUNC_SEW,  /* Truncate to log(SEW) bits */
1235    IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */
1236} imm_mode_t;
1237
1238static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode)
1239{
1240    switch (imm_mode) {
1241    case IMM_ZX:
1242        return extract64(imm, 0, 5);
1243    case IMM_SX:
1244        return sextract64(imm, 0, 5);
1245    case IMM_TRUNC_SEW:
1246        return extract64(imm, 0, s->sew + 3);
1247    case IMM_TRUNC_2SEW:
1248        return extract64(imm, 0, s->sew + 4);
1249    default:
1250        g_assert_not_reached();
1251    }
1252}
1253
1254static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1255                        gen_helper_opivx *fn, DisasContext *s,
1256                        imm_mode_t imm_mode)
1257{
1258    TCGv_ptr dest, src2, mask;
1259    TCGv src1;
1260    TCGv_i32 desc;
1261    uint32_t data = 0;
1262
1263    TCGLabel *over = gen_new_label();
1264    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1265
1266    dest = tcg_temp_new_ptr();
1267    mask = tcg_temp_new_ptr();
1268    src2 = tcg_temp_new_ptr();
1269    src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode));
1270
1271    data = FIELD_DP32(data, VDATA, VM, vm);
1272    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1273    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1274
1275    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1276    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1277    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1278
1279    fn(dest, mask, src1, src2, cpu_env, desc);
1280
1281    tcg_temp_free_ptr(dest);
1282    tcg_temp_free_ptr(mask);
1283    tcg_temp_free_ptr(src2);
1284    mark_vs_dirty(s);
1285    gen_set_label(over);
1286    return true;
1287}
1288
1289typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1290                         uint32_t, uint32_t);
1291
1292static inline bool
1293do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1294              gen_helper_opivx *fn, imm_mode_t imm_mode)
1295{
1296    if (!opivx_check(s, a)) {
1297        return false;
1298    }
1299
1300    if (a->vm && s->vl_eq_vlmax) {
1301        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1302                extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
1303        mark_vs_dirty(s);
1304        return true;
1305    }
1306    return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode);
1307}
1308
1309/* OPIVI with GVEC IR */
1310#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \
1311static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1312{                                                                  \
1313    static gen_helper_opivx * const fns[4] = {                     \
1314        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1315        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1316    };                                                             \
1317    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1318                         fns[s->sew], IMM_MODE);                   \
1319}
1320
1321GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi)
1322
1323static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1324                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1325{
1326    TCGv_i64 tmp = tcg_constant_i64(c);
1327    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1328}
1329
1330GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi)
1331
1332/* Vector Widening Integer Add/Subtract */
1333
1334/* OPIVV with WIDEN */
1335static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1336{
1337    return require_rvv(s) &&
1338           vext_check_isa_ill(s) &&
1339           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
1340}
1341
1342static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1343                           gen_helper_gvec_4_ptr *fn,
1344                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1345{
1346    if (checkfn(s, a)) {
1347        uint32_t data = 0;
1348        TCGLabel *over = gen_new_label();
1349        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1350
1351        data = FIELD_DP32(data, VDATA, VM, a->vm);
1352        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1353        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1354                           vreg_ofs(s, a->rs1),
1355                           vreg_ofs(s, a->rs2),
1356                           cpu_env, s->vlen / 8, s->vlen / 8,
1357                           data, fn);
1358        mark_vs_dirty(s);
1359        gen_set_label(over);
1360        return true;
1361    }
1362    return false;
1363}
1364
1365#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1366static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1367{                                                            \
1368    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1369        gen_helper_##NAME##_b,                               \
1370        gen_helper_##NAME##_h,                               \
1371        gen_helper_##NAME##_w                                \
1372    };                                                       \
1373    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1374}
1375
1376GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1377GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1378GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1379GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1380
1381/* OPIVX with WIDEN */
1382static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1383{
1384    return require_rvv(s) &&
1385           vext_check_isa_ill(s) &&
1386           vext_check_ds(s, a->rd, a->rs2, a->vm);
1387}
1388
1389static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1390                           gen_helper_opivx *fn)
1391{
1392    if (opivx_widen_check(s, a)) {
1393        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1394    }
1395    return false;
1396}
1397
1398#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1399static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1400{                                                            \
1401    static gen_helper_opivx * const fns[3] = {               \
1402        gen_helper_##NAME##_b,                               \
1403        gen_helper_##NAME##_h,                               \
1404        gen_helper_##NAME##_w                                \
1405    };                                                       \
1406    return do_opivx_widen(s, a, fns[s->sew]);                \
1407}
1408
1409GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1410GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1411GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1412GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1413
1414/* WIDEN OPIVV with WIDEN */
1415static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1416{
1417    return require_rvv(s) &&
1418           vext_check_isa_ill(s) &&
1419           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
1420}
1421
1422static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1423                           gen_helper_gvec_4_ptr *fn)
1424{
1425    if (opiwv_widen_check(s, a)) {
1426        uint32_t data = 0;
1427        TCGLabel *over = gen_new_label();
1428        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1429
1430        data = FIELD_DP32(data, VDATA, VM, a->vm);
1431        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1432        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1433                           vreg_ofs(s, a->rs1),
1434                           vreg_ofs(s, a->rs2),
1435                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1436        mark_vs_dirty(s);
1437        gen_set_label(over);
1438        return true;
1439    }
1440    return false;
1441}
1442
1443#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1444static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1445{                                                            \
1446    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1447        gen_helper_##NAME##_b,                               \
1448        gen_helper_##NAME##_h,                               \
1449        gen_helper_##NAME##_w                                \
1450    };                                                       \
1451    return do_opiwv_widen(s, a, fns[s->sew]);                \
1452}
1453
1454GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1455GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1456GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1457GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1458
1459/* WIDEN OPIVX with WIDEN */
1460static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1461{
1462    return require_rvv(s) &&
1463           vext_check_isa_ill(s) &&
1464           vext_check_dd(s, a->rd, a->rs2, a->vm);
1465}
1466
1467static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1468                           gen_helper_opivx *fn)
1469{
1470    if (opiwx_widen_check(s, a)) {
1471        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1472    }
1473    return false;
1474}
1475
1476#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1477static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1478{                                                            \
1479    static gen_helper_opivx * const fns[3] = {               \
1480        gen_helper_##NAME##_b,                               \
1481        gen_helper_##NAME##_h,                               \
1482        gen_helper_##NAME##_w                                \
1483    };                                                       \
1484    return do_opiwx_widen(s, a, fns[s->sew]);                \
1485}
1486
1487GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1488GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1489GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1490GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1491
1492/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1493/* OPIVV without GVEC IR */
1494#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1495static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1496{                                                                  \
1497    if (CHECK(s, a)) {                                             \
1498        uint32_t data = 0;                                         \
1499        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1500            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1501            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1502        };                                                         \
1503        TCGLabel *over = gen_new_label();                          \
1504        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1505                                                                   \
1506        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1507        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1508        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1509                           vreg_ofs(s, a->rs1),                    \
1510                           vreg_ofs(s, a->rs2), cpu_env,           \
1511                           s->vlen / 8, s->vlen / 8, data,         \
1512                           fns[s->sew]);                           \
1513        mark_vs_dirty(s);                                          \
1514        gen_set_label(over);                                       \
1515        return true;                                               \
1516    }                                                              \
1517    return false;                                                  \
1518}
1519
1520/*
1521 * For vadc and vsbc, an illegal instruction exception is raised if the
1522 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1523 */
1524static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1525{
1526    return require_rvv(s) &&
1527           vext_check_isa_ill(s) &&
1528           (a->rd != 0) &&
1529           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1530}
1531
1532GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1533GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1534
1535/*
1536 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1537 * destination vector register overlaps a source vector register group.
1538 */
1539static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1540{
1541    return require_rvv(s) &&
1542           vext_check_isa_ill(s) &&
1543           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1544}
1545
1546GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1547GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1548
1549static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1550{
1551    return require_rvv(s) &&
1552           vext_check_isa_ill(s) &&
1553           (a->rd != 0) &&
1554           vext_check_ss(s, a->rd, a->rs2, a->vm);
1555}
1556
1557/* OPIVX without GVEC IR */
1558#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1559static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1560{                                                                        \
1561    if (CHECK(s, a)) {                                                   \
1562        static gen_helper_opivx * const fns[4] = {                       \
1563            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1564            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1565        };                                                               \
1566                                                                         \
1567        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1568    }                                                                    \
1569    return false;                                                        \
1570}
1571
1572GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1573GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1574
1575static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1576{
1577    return require_rvv(s) &&
1578           vext_check_isa_ill(s) &&
1579           vext_check_ms(s, a->rd, a->rs2);
1580}
1581
1582GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1583GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1584
1585/* OPIVI without GVEC IR */
1586#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK)                    \
1587static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1588{                                                                        \
1589    if (CHECK(s, a)) {                                                   \
1590        static gen_helper_opivx * const fns[4] = {                       \
1591            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1592            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1593        };                                                               \
1594        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1595                           fns[s->sew], s, IMM_MODE);                    \
1596    }                                                                    \
1597    return false;                                                        \
1598}
1599
1600GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check)
1601GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check)
1602
1603/* Vector Bitwise Logical Instructions */
1604GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1605GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1606GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1607GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1608GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1609GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1610GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi)
1611GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx,  ori)
1612GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori)
1613
1614/* Vector Single-Width Bit Shift Instructions */
1615GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1616GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1617GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1618
1619typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1620                           uint32_t, uint32_t);
1621
1622static inline bool
1623do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1624                    gen_helper_opivx *fn)
1625{
1626    if (!opivx_check(s, a)) {
1627        return false;
1628    }
1629
1630    if (a->vm && s->vl_eq_vlmax) {
1631        TCGv_i32 src1 = tcg_temp_new_i32();
1632
1633        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1634        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1635        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1636                src1, MAXSZ(s), MAXSZ(s));
1637
1638        tcg_temp_free_i32(src1);
1639        mark_vs_dirty(s);
1640        return true;
1641    }
1642    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1643}
1644
1645#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1646static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1647{                                                                         \
1648    static gen_helper_opivx * const fns[4] = {                            \
1649        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1650        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1651    };                                                                    \
1652                                                                          \
1653    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1654}
1655
1656GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1657GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1658GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1659
1660GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_ZX, vsll_vx, shli)
1661GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_ZX, vsrl_vx, shri)
1662GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_ZX, vsra_vx, sari)
1663
1664/* Vector Narrowing Integer Right Shift Instructions */
1665static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
1666{
1667    return require_rvv(s) &&
1668           vext_check_isa_ill(s) &&
1669           vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm);
1670}
1671
1672/* OPIVV with NARROW */
1673#define GEN_OPIVV_NARROW_TRANS(NAME)                               \
1674static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1675{                                                                  \
1676    if (opivv_narrow_check(s, a)) {                                \
1677        uint32_t data = 0;                                         \
1678        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1679            gen_helper_##NAME##_b,                                 \
1680            gen_helper_##NAME##_h,                                 \
1681            gen_helper_##NAME##_w,                                 \
1682        };                                                         \
1683        TCGLabel *over = gen_new_label();                          \
1684        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1685                                                                   \
1686        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1687        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1688        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1689                           vreg_ofs(s, a->rs1),                    \
1690                           vreg_ofs(s, a->rs2), cpu_env,           \
1691                           s->vlen / 8, s->vlen / 8, data,         \
1692                           fns[s->sew]);                           \
1693        mark_vs_dirty(s);                                          \
1694        gen_set_label(over);                                       \
1695        return true;                                               \
1696    }                                                              \
1697    return false;                                                  \
1698}
1699GEN_OPIVV_NARROW_TRANS(vnsra_vv)
1700GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
1701
1702static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
1703{
1704    return require_rvv(s) &&
1705           vext_check_isa_ill(s) &&
1706           vext_check_sd(s, a->rd, a->rs2, a->vm);
1707}
1708
1709/* OPIVX with NARROW */
1710#define GEN_OPIVX_NARROW_TRANS(NAME)                                     \
1711static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1712{                                                                        \
1713    if (opivx_narrow_check(s, a)) {                                      \
1714        static gen_helper_opivx * const fns[3] = {                       \
1715            gen_helper_##NAME##_b,                                       \
1716            gen_helper_##NAME##_h,                                       \
1717            gen_helper_##NAME##_w,                                       \
1718        };                                                               \
1719        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1720    }                                                                    \
1721    return false;                                                        \
1722}
1723
1724GEN_OPIVX_NARROW_TRANS(vnsra_vx)
1725GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
1726
1727/* OPIVI with NARROW */
1728#define GEN_OPIVI_NARROW_TRANS(NAME, IMM_MODE, OPIVX)                    \
1729static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1730{                                                                        \
1731    if (opivx_narrow_check(s, a)) {                                      \
1732        static gen_helper_opivx * const fns[3] = {                       \
1733            gen_helper_##OPIVX##_b,                                      \
1734            gen_helper_##OPIVX##_h,                                      \
1735            gen_helper_##OPIVX##_w,                                      \
1736        };                                                               \
1737        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1738                           fns[s->sew], s, IMM_MODE);                    \
1739    }                                                                    \
1740    return false;                                                        \
1741}
1742
1743GEN_OPIVI_NARROW_TRANS(vnsra_vi, IMM_ZX, vnsra_vx)
1744GEN_OPIVI_NARROW_TRANS(vnsrl_vi, IMM_ZX, vnsrl_vx)
1745
1746/* Vector Integer Comparison Instructions */
1747/*
1748 * For all comparison instructions, an illegal instruction exception is raised
1749 * if the destination vector register overlaps a source vector register group
1750 * and LMUL > 1.
1751 */
1752static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1753{
1754    return require_rvv(s) &&
1755           vext_check_isa_ill(s) &&
1756           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1757}
1758
1759GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1760GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1761GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1762GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1763GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1764GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1765
1766static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1767{
1768    return require_rvv(s) &&
1769           vext_check_isa_ill(s) &&
1770           vext_check_ms(s, a->rd, a->rs2);
1771}
1772
1773GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1774GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1775GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1776GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1777GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1778GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1779GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1780GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1781
1782GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check)
1783GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check)
1784GEN_OPIVI_TRANS(vmsleu_vi, IMM_ZX, vmsleu_vx, opivx_cmp_check)
1785GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check)
1786GEN_OPIVI_TRANS(vmsgtu_vi, IMM_ZX, vmsgtu_vx, opivx_cmp_check)
1787GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check)
1788
1789/* Vector Integer Min/Max Instructions */
1790GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1791GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1792GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1793GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1794GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1795GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1796GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1797GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1798
1799/* Vector Single-Width Integer Multiply Instructions */
1800GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1801GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1802GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1803GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1804GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1805GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1806GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1807GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1808
1809/* Vector Integer Divide Instructions */
1810GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1811GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1812GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1813GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1814GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1815GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1816GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1817GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1818
1819/* Vector Widening Integer Multiply Instructions */
1820GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1821GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1822GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1823GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1824GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1825GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1826
1827/* Vector Single-Width Integer Multiply-Add Instructions */
1828GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1829GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1830GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1831GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1832GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1833GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1834GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1835GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1836
1837/* Vector Widening Integer Multiply-Add Instructions */
1838GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1839GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1840GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1841GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1842GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1843GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1844GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1845
1846/* Vector Integer Merge and Move Instructions */
1847static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1848{
1849    if (require_rvv(s) &&
1850        vext_check_isa_ill(s) &&
1851        /* vmv.v.v has rs2 = 0 and vm = 1 */
1852        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
1853        if (s->vl_eq_vlmax) {
1854            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1855                             vreg_ofs(s, a->rs1),
1856                             MAXSZ(s), MAXSZ(s));
1857        } else {
1858            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1859            static gen_helper_gvec_2_ptr * const fns[4] = {
1860                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1861                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1862            };
1863            TCGLabel *over = gen_new_label();
1864            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1865
1866            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1867                               cpu_env, s->vlen / 8, s->vlen / 8, data,
1868                               fns[s->sew]);
1869            gen_set_label(over);
1870        }
1871        mark_vs_dirty(s);
1872        return true;
1873    }
1874    return false;
1875}
1876
1877typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1878static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1879{
1880    if (require_rvv(s) &&
1881        vext_check_isa_ill(s) &&
1882        /* vmv.v.x has rs2 = 0 and vm = 1 */
1883        vext_check_ss(s, a->rd, 0, 1)) {
1884        TCGv s1;
1885        TCGLabel *over = gen_new_label();
1886        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1887
1888        s1 = get_gpr(s, a->rs1, EXT_SIGN);
1889
1890        if (s->vl_eq_vlmax) {
1891            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1892                                MAXSZ(s), MAXSZ(s), s1);
1893        } else {
1894            TCGv_i32 desc;
1895            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1896            TCGv_ptr dest = tcg_temp_new_ptr();
1897            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1898            static gen_helper_vmv_vx * const fns[4] = {
1899                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1900                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1901            };
1902
1903            tcg_gen_ext_tl_i64(s1_i64, s1);
1904            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1905            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1906            fns[s->sew](dest, s1_i64, cpu_env, desc);
1907
1908            tcg_temp_free_ptr(dest);
1909            tcg_temp_free_i64(s1_i64);
1910        }
1911
1912        mark_vs_dirty(s);
1913        gen_set_label(over);
1914        return true;
1915    }
1916    return false;
1917}
1918
1919static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
1920{
1921    if (require_rvv(s) &&
1922        vext_check_isa_ill(s) &&
1923        /* vmv.v.i has rs2 = 0 and vm = 1 */
1924        vext_check_ss(s, a->rd, 0, 1)) {
1925        int64_t simm = sextract64(a->rs1, 0, 5);
1926        if (s->vl_eq_vlmax) {
1927            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
1928                                 MAXSZ(s), MAXSZ(s), simm);
1929            mark_vs_dirty(s);
1930        } else {
1931            TCGv_i32 desc;
1932            TCGv_i64 s1;
1933            TCGv_ptr dest;
1934            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1935            static gen_helper_vmv_vx * const fns[4] = {
1936                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1937                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1938            };
1939            TCGLabel *over = gen_new_label();
1940            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1941
1942            s1 = tcg_constant_i64(simm);
1943            dest = tcg_temp_new_ptr();
1944            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1945            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1946            fns[s->sew](dest, s1, cpu_env, desc);
1947
1948            tcg_temp_free_ptr(dest);
1949            mark_vs_dirty(s);
1950            gen_set_label(over);
1951        }
1952        return true;
1953    }
1954    return false;
1955}
1956
1957GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
1958GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
1959GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
1960
1961/*
1962 *** Vector Fixed-Point Arithmetic Instructions
1963 */
1964
1965/* Vector Single-Width Saturating Add and Subtract */
1966GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
1967GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
1968GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
1969GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
1970GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
1971GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
1972GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
1973GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
1974GEN_OPIVI_TRANS(vsaddu_vi, IMM_ZX, vsaddu_vx, opivx_check)
1975GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
1976
1977/* Vector Single-Width Averaging Add and Subtract */
1978GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
1979GEN_OPIVV_TRANS(vasub_vv, opivv_check)
1980GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
1981GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
1982GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
1983
1984/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1985GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
1986GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
1987
1988/* Vector Widening Saturating Scaled Multiply-Add */
1989GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
1990GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
1991GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
1992GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
1993GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
1994GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
1995GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
1996
1997/* Vector Single-Width Scaling Shift Instructions */
1998GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
1999GEN_OPIVV_TRANS(vssra_vv, opivv_check)
2000GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
2001GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
2002GEN_OPIVI_TRANS(vssrl_vi, IMM_ZX, vssrl_vx, opivx_check)
2003GEN_OPIVI_TRANS(vssra_vi, IMM_SX, vssra_vx, opivx_check)
2004
2005/* Vector Narrowing Fixed-Point Clip Instructions */
2006GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
2007GEN_OPIVV_NARROW_TRANS(vnclip_vv)
2008GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
2009GEN_OPIVX_NARROW_TRANS(vnclip_vx)
2010GEN_OPIVI_NARROW_TRANS(vnclipu_vi, IMM_ZX, vnclipu_vx)
2011GEN_OPIVI_NARROW_TRANS(vnclip_vi, IMM_ZX, vnclip_vx)
2012
2013/*
2014 *** Vector Float Point Arithmetic Instructions
2015 */
2016
2017/*
2018 * As RVF-only cpus always have values NaN-boxed to 64-bits,
2019 * RVF and RVD can be treated equally.
2020 * We don't have to deal with the cases of: SEW > FLEN.
2021 *
2022 * If SEW < FLEN, check whether input fp register is a valid
2023 * NaN-boxed value, in which case the least-significant SEW bits
2024 * of the f regsiter are used, else the canonical NaN value is used.
2025 */
2026static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
2027{
2028    switch (s->sew) {
2029    case 1:
2030        gen_check_nanbox_h(out, in);
2031        break;
2032    case 2:
2033        gen_check_nanbox_s(out, in);
2034        break;
2035    case 3:
2036        tcg_gen_mov_i64(out, in);
2037        break;
2038    default:
2039        g_assert_not_reached();
2040    }
2041}
2042
2043/* Vector Single-Width Floating-Point Add/Subtract Instructions */
2044
2045/*
2046 * If the current SEW does not correspond to a supported IEEE floating-point
2047 * type, an illegal instruction exception is raised.
2048 */
2049static bool opfvv_check(DisasContext *s, arg_rmrr *a)
2050{
2051    return require_rvv(s) &&
2052           require_rvf(s) &&
2053           vext_check_isa_ill(s) &&
2054           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
2055}
2056
2057/* OPFVV without GVEC IR */
2058#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2059static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2060{                                                                  \
2061    if (CHECK(s, a)) {                                             \
2062        uint32_t data = 0;                                         \
2063        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2064            gen_helper_##NAME##_h,                                 \
2065            gen_helper_##NAME##_w,                                 \
2066            gen_helper_##NAME##_d,                                 \
2067        };                                                         \
2068        TCGLabel *over = gen_new_label();                          \
2069        gen_set_rm(s, 7);                                          \
2070        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2071                                                                   \
2072        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2073        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2074        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2075                           vreg_ofs(s, a->rs1),                    \
2076                           vreg_ofs(s, a->rs2), cpu_env,           \
2077                           s->vlen / 8, s->vlen / 8, data,         \
2078                           fns[s->sew - 1]);                       \
2079        mark_vs_dirty(s);                                          \
2080        gen_set_label(over);                                       \
2081        return true;                                               \
2082    }                                                              \
2083    return false;                                                  \
2084}
2085GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2086GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2087
2088typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2089                              TCGv_env, TCGv_i32);
2090
2091static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2092                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2093{
2094    TCGv_ptr dest, src2, mask;
2095    TCGv_i32 desc;
2096    TCGv_i64 t1;
2097
2098    TCGLabel *over = gen_new_label();
2099    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2100
2101    dest = tcg_temp_new_ptr();
2102    mask = tcg_temp_new_ptr();
2103    src2 = tcg_temp_new_ptr();
2104    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2105
2106    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2107    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2108    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2109
2110    /* NaN-box f[rs1] */
2111    t1 = tcg_temp_new_i64();
2112    do_nanbox(s, t1, cpu_fpr[rs1]);
2113
2114    fn(dest, mask, t1, src2, cpu_env, desc);
2115
2116    tcg_temp_free_ptr(dest);
2117    tcg_temp_free_ptr(mask);
2118    tcg_temp_free_ptr(src2);
2119    tcg_temp_free_i64(t1);
2120    mark_vs_dirty(s);
2121    gen_set_label(over);
2122    return true;
2123}
2124
2125/*
2126 * If the current SEW does not correspond to a supported IEEE floating-point
2127 * type, an illegal instruction exception is raised
2128 */
2129static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2130{
2131    return require_rvv(s) &&
2132           require_rvf(s) &&
2133           vext_check_isa_ill(s) &&
2134           vext_check_ss(s, a->rd, a->rs2, a->vm);
2135}
2136
2137/* OPFVF without GVEC IR */
2138#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2139static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2140{                                                                 \
2141    if (CHECK(s, a)) {                                            \
2142        uint32_t data = 0;                                        \
2143        static gen_helper_opfvf *const fns[3] = {                 \
2144            gen_helper_##NAME##_h,                                \
2145            gen_helper_##NAME##_w,                                \
2146            gen_helper_##NAME##_d,                                \
2147        };                                                        \
2148        gen_set_rm(s, 7);                                         \
2149        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2150        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2151        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2152                           fns[s->sew - 1], s);                   \
2153    }                                                             \
2154    return false;                                                 \
2155}
2156
2157GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2158GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2159GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2160
2161/* Vector Widening Floating-Point Add/Subtract Instructions */
2162static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2163{
2164    return require_rvv(s) &&
2165           require_rvf(s) &&
2166           vext_check_isa_ill(s) &&
2167           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2168}
2169
2170/* OPFVV with WIDEN */
2171#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2172static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2173{                                                                \
2174    if (CHECK(s, a)) {                                           \
2175        uint32_t data = 0;                                       \
2176        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2177            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2178        };                                                       \
2179        TCGLabel *over = gen_new_label();                        \
2180        gen_set_rm(s, 7);                                        \
2181        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2182                                                                 \
2183        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2184        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2185        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2186                           vreg_ofs(s, a->rs1),                  \
2187                           vreg_ofs(s, a->rs2), cpu_env,         \
2188                           s->vlen / 8, s->vlen / 8, data,       \
2189                           fns[s->sew - 1]);                     \
2190        mark_vs_dirty(s);                                        \
2191        gen_set_label(over);                                     \
2192        return true;                                             \
2193    }                                                            \
2194    return false;                                                \
2195}
2196
2197GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2198GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2199
2200static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2201{
2202    return require_rvv(s) &&
2203           require_rvf(s) &&
2204           vext_check_isa_ill(s) &&
2205           vext_check_ds(s, a->rd, a->rs2, a->vm);
2206}
2207
2208/* OPFVF with WIDEN */
2209#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2210static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2211{                                                                \
2212    if (opfvf_widen_check(s, a)) {                               \
2213        uint32_t data = 0;                                       \
2214        static gen_helper_opfvf *const fns[2] = {                \
2215            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2216        };                                                       \
2217        gen_set_rm(s, 7);                                        \
2218        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2219        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2220        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2221                           fns[s->sew - 1], s);                  \
2222    }                                                            \
2223    return false;                                                \
2224}
2225
2226GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2227GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2228
2229static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2230{
2231    return require_rvv(s) &&
2232           require_rvf(s) &&
2233           vext_check_isa_ill(s) &&
2234           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2235}
2236
2237/* WIDEN OPFVV with WIDEN */
2238#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2239static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2240{                                                                  \
2241    if (opfwv_widen_check(s, a)) {                                 \
2242        uint32_t data = 0;                                         \
2243        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2244            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2245        };                                                         \
2246        TCGLabel *over = gen_new_label();                          \
2247        gen_set_rm(s, 7);                                          \
2248        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2249                                                                   \
2250        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2251        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2252        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2253                           vreg_ofs(s, a->rs1),                    \
2254                           vreg_ofs(s, a->rs2), cpu_env,           \
2255                           s->vlen / 8, s->vlen / 8, data,         \
2256                           fns[s->sew - 1]);                       \
2257        mark_vs_dirty(s);                                          \
2258        gen_set_label(over);                                       \
2259        return true;                                               \
2260    }                                                              \
2261    return false;                                                  \
2262}
2263
2264GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2265GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2266
2267static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2268{
2269    return require_rvv(s) &&
2270           require_rvf(s) &&
2271           vext_check_isa_ill(s) &&
2272           vext_check_dd(s, a->rd, a->rs2, a->vm);
2273}
2274
2275/* WIDEN OPFVF with WIDEN */
2276#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2277static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2278{                                                                \
2279    if (opfwf_widen_check(s, a)) {                               \
2280        uint32_t data = 0;                                       \
2281        static gen_helper_opfvf *const fns[2] = {                \
2282            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2283        };                                                       \
2284        gen_set_rm(s, 7);                                        \
2285        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2286        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2287        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2288                           fns[s->sew - 1], s);                  \
2289    }                                                            \
2290    return false;                                                \
2291}
2292
2293GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2294GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2295
2296/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2297GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2298GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2299GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2300GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2301GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2302
2303/* Vector Widening Floating-Point Multiply */
2304GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2305GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2306
2307/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2308GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2309GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2310GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2311GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2312GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2313GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2314GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2315GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2316GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2317GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2318GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2319GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2320GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2321GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2322GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2323GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2324
2325/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2326GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2327GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2328GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2329GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2330GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2331GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2332GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2333GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2334
2335/* Vector Floating-Point Square-Root Instruction */
2336
2337/*
2338 * If the current SEW does not correspond to a supported IEEE floating-point
2339 * type, an illegal instruction exception is raised
2340 */
2341static bool opfv_check(DisasContext *s, arg_rmr *a)
2342{
2343    return require_rvv(s) &&
2344           require_rvf(s) &&
2345           vext_check_isa_ill(s) &&
2346           /* OPFV instructions ignore vs1 check */
2347           vext_check_ss(s, a->rd, a->rs2, a->vm);
2348}
2349
2350#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2351static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2352{                                                                  \
2353    if (CHECK(s, a)) {                                             \
2354        uint32_t data = 0;                                         \
2355        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2356            gen_helper_##NAME##_h,                                 \
2357            gen_helper_##NAME##_w,                                 \
2358            gen_helper_##NAME##_d,                                 \
2359        };                                                         \
2360        TCGLabel *over = gen_new_label();                          \
2361        gen_set_rm(s, 7);                                          \
2362        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2363                                                                   \
2364        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2365        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2366        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2367                           vreg_ofs(s, a->rs2), cpu_env,           \
2368                           s->vlen / 8, s->vlen / 8, data,         \
2369                           fns[s->sew - 1]);                       \
2370        mark_vs_dirty(s);                                          \
2371        gen_set_label(over);                                       \
2372        return true;                                               \
2373    }                                                              \
2374    return false;                                                  \
2375}
2376
2377GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2378
2379/* Vector Floating-Point MIN/MAX Instructions */
2380GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2381GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2382GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2383GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2384
2385/* Vector Floating-Point Sign-Injection Instructions */
2386GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2387GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2388GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2389GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2390GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2391GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2392
2393/* Vector Floating-Point Compare Instructions */
2394static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2395{
2396    return require_rvv(s) &&
2397           require_rvf(s) &&
2398           vext_check_isa_ill(s) &&
2399           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2400}
2401
2402GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2403GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2404GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2405GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2406GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2407
2408static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2409{
2410    return require_rvv(s) &&
2411           require_rvf(s) &&
2412           vext_check_isa_ill(s) &&
2413           vext_check_ms(s, a->rd, a->rs2);
2414}
2415
2416GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2417GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2418GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2419GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2420GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2421GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2422GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2423
2424/* Vector Floating-Point Classify Instruction */
2425GEN_OPFV_TRANS(vfclass_v, opfv_check)
2426
2427/* Vector Floating-Point Merge Instruction */
2428GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2429
2430static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2431{
2432    if (require_rvv(s) &&
2433        require_rvf(s) &&
2434        vext_check_isa_ill(s) &&
2435        require_align(a->rd, s->lmul)) {
2436        if (s->vl_eq_vlmax) {
2437            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2438                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2439            mark_vs_dirty(s);
2440        } else {
2441            TCGv_ptr dest;
2442            TCGv_i32 desc;
2443            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2444            static gen_helper_vmv_vx * const fns[3] = {
2445                gen_helper_vmv_v_x_h,
2446                gen_helper_vmv_v_x_w,
2447                gen_helper_vmv_v_x_d,
2448            };
2449            TCGLabel *over = gen_new_label();
2450            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2451
2452            dest = tcg_temp_new_ptr();
2453            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2454            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2455            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2456
2457            tcg_temp_free_ptr(dest);
2458            mark_vs_dirty(s);
2459            gen_set_label(over);
2460        }
2461        return true;
2462    }
2463    return false;
2464}
2465
2466/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2467GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2468GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2469GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2470GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2471
2472/* Widening Floating-Point/Integer Type-Convert Instructions */
2473
2474/*
2475 * If the current SEW does not correspond to a supported IEEE floating-point
2476 * type, an illegal instruction exception is raised
2477 */
2478static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2479{
2480    return require_rvv(s) &&
2481           require_scale_rvf(s) &&
2482           (s->sew != MO_8) &&
2483           vext_check_isa_ill(s) &&
2484           vext_check_ds(s, a->rd, a->rs2, a->vm);
2485}
2486
2487#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2488static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2489{                                                                  \
2490    if (opfv_widen_check(s, a)) {                                  \
2491        uint32_t data = 0;                                         \
2492        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2493            gen_helper_##NAME##_h,                                 \
2494            gen_helper_##NAME##_w,                                 \
2495        };                                                         \
2496        TCGLabel *over = gen_new_label();                          \
2497        gen_set_rm(s, 7);                                          \
2498        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2499                                                                   \
2500        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2501        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2502        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2503                           vreg_ofs(s, a->rs2), cpu_env,           \
2504                           s->vlen / 8, s->vlen / 8, data,         \
2505                           fns[s->sew - 1]);                       \
2506        mark_vs_dirty(s);                                          \
2507        gen_set_label(over);                                       \
2508        return true;                                               \
2509    }                                                              \
2510    return false;                                                  \
2511}
2512
2513GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2514GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2515GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2516GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2517GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2518
2519/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2520
2521/*
2522 * If the current SEW does not correspond to a supported IEEE floating-point
2523 * type, an illegal instruction exception is raised
2524 */
2525static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2526{
2527    return require_rvv(s) &&
2528           require_rvf(s) &&
2529           (s->sew != MO_64) &&
2530           vext_check_isa_ill(s) &&
2531           /* OPFV narrowing instructions ignore vs1 check */
2532           vext_check_sd(s, a->rd, a->rs2, a->vm);
2533}
2534
2535#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2536static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2537{                                                                  \
2538    if (opfv_narrow_check(s, a)) {                                 \
2539        uint32_t data = 0;                                         \
2540        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2541            gen_helper_##NAME##_h,                                 \
2542            gen_helper_##NAME##_w,                                 \
2543        };                                                         \
2544        TCGLabel *over = gen_new_label();                          \
2545        gen_set_rm(s, 7);                                          \
2546        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2547                                                                   \
2548        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2549        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2550        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2551                           vreg_ofs(s, a->rs2), cpu_env,           \
2552                           s->vlen / 8, s->vlen / 8, data,         \
2553                           fns[s->sew - 1]);                       \
2554        mark_vs_dirty(s);                                          \
2555        gen_set_label(over);                                       \
2556        return true;                                               \
2557    }                                                              \
2558    return false;                                                  \
2559}
2560
2561GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2562GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2563GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2564GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2565GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2566
2567/*
2568 *** Vector Reduction Operations
2569 */
2570/* Vector Single-Width Integer Reduction Instructions */
2571static bool reduction_check(DisasContext *s, arg_rmrr *a)
2572{
2573    return require_rvv(s) &&
2574           vext_check_isa_ill(s) &&
2575           vext_check_reduction(s, a->rs2);
2576}
2577
2578GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2579GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2580GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2581GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2582GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2583GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2584GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2585GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2586
2587/* Vector Widening Integer Reduction Instructions */
2588static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
2589{
2590    return reduction_check(s, a) && (s->sew < MO_64);
2591}
2592
2593GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
2594GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
2595
2596/* Vector Single-Width Floating-Point Reduction Instructions */
2597GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2598GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2599GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2600
2601/* Vector Widening Floating-Point Reduction Instructions */
2602GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2603
2604/*
2605 *** Vector Mask Operations
2606 */
2607
2608/* Vector Mask-Register Logical Instructions */
2609#define GEN_MM_TRANS(NAME)                                         \
2610static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2611{                                                                  \
2612    if (vext_check_isa_ill(s)) {                                   \
2613        uint32_t data = 0;                                         \
2614        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2615        TCGLabel *over = gen_new_label();                          \
2616        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2617                                                                   \
2618        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2619        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2620                           vreg_ofs(s, a->rs1),                    \
2621                           vreg_ofs(s, a->rs2), cpu_env,           \
2622                           s->vlen / 8, s->vlen / 8, data, fn);    \
2623        mark_vs_dirty(s);                                          \
2624        gen_set_label(over);                                       \
2625        return true;                                               \
2626    }                                                              \
2627    return false;                                                  \
2628}
2629
2630GEN_MM_TRANS(vmand_mm)
2631GEN_MM_TRANS(vmnand_mm)
2632GEN_MM_TRANS(vmandnot_mm)
2633GEN_MM_TRANS(vmxor_mm)
2634GEN_MM_TRANS(vmor_mm)
2635GEN_MM_TRANS(vmnor_mm)
2636GEN_MM_TRANS(vmornot_mm)
2637GEN_MM_TRANS(vmxnor_mm)
2638
2639/* Vector mask population count vmpopc */
2640static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2641{
2642    if (require_rvv(s) &&
2643        vext_check_isa_ill(s)) {
2644        TCGv_ptr src2, mask;
2645        TCGv dst;
2646        TCGv_i32 desc;
2647        uint32_t data = 0;
2648        data = FIELD_DP32(data, VDATA, VM, a->vm);
2649        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2650
2651        mask = tcg_temp_new_ptr();
2652        src2 = tcg_temp_new_ptr();
2653        dst = dest_gpr(s, a->rd);
2654        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2655
2656        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2657        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2658
2659        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2660        gen_set_gpr(s, a->rd, dst);
2661
2662        tcg_temp_free_ptr(mask);
2663        tcg_temp_free_ptr(src2);
2664        return true;
2665    }
2666    return false;
2667}
2668
2669/* vmfirst find-first-set mask bit */
2670static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2671{
2672    if (require_rvv(s) &&
2673        vext_check_isa_ill(s)) {
2674        TCGv_ptr src2, mask;
2675        TCGv dst;
2676        TCGv_i32 desc;
2677        uint32_t data = 0;
2678        data = FIELD_DP32(data, VDATA, VM, a->vm);
2679        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2680
2681        mask = tcg_temp_new_ptr();
2682        src2 = tcg_temp_new_ptr();
2683        dst = dest_gpr(s, a->rd);
2684        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2685
2686        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2687        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2688
2689        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2690        gen_set_gpr(s, a->rd, dst);
2691
2692        tcg_temp_free_ptr(mask);
2693        tcg_temp_free_ptr(src2);
2694        return true;
2695    }
2696    return false;
2697}
2698
2699/* vmsbf.m set-before-first mask bit */
2700/* vmsif.m set-includ-first mask bit */
2701/* vmsof.m set-only-first mask bit */
2702#define GEN_M_TRANS(NAME)                                          \
2703static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2704{                                                                  \
2705    if (vext_check_isa_ill(s)) {                                   \
2706        uint32_t data = 0;                                         \
2707        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2708        TCGLabel *over = gen_new_label();                          \
2709        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2710                                                                   \
2711        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2712        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2713        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2714                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2715                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2716                           data, fn);                              \
2717        mark_vs_dirty(s);                                          \
2718        gen_set_label(over);                                       \
2719        return true;                                               \
2720    }                                                              \
2721    return false;                                                  \
2722}
2723
2724GEN_M_TRANS(vmsbf_m)
2725GEN_M_TRANS(vmsif_m)
2726GEN_M_TRANS(vmsof_m)
2727
2728/* Vector Iota Instruction */
2729static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2730{
2731    if (require_rvv(s) &&
2732        vext_check_isa_ill(s) &&
2733        require_noover(a->rd, s->lmul, a->rs2, 0) &&
2734        require_vm(a->vm, a->rd) &&
2735        require_align(a->rd, s->lmul)) {
2736        uint32_t data = 0;
2737        TCGLabel *over = gen_new_label();
2738        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2739
2740        data = FIELD_DP32(data, VDATA, VM, a->vm);
2741        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2742        static gen_helper_gvec_3_ptr * const fns[4] = {
2743            gen_helper_viota_m_b, gen_helper_viota_m_h,
2744            gen_helper_viota_m_w, gen_helper_viota_m_d,
2745        };
2746        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2747                           vreg_ofs(s, a->rs2), cpu_env,
2748                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2749        mark_vs_dirty(s);
2750        gen_set_label(over);
2751        return true;
2752    }
2753    return false;
2754}
2755
2756/* Vector Element Index Instruction */
2757static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2758{
2759    if (require_rvv(s) &&
2760        vext_check_isa_ill(s) &&
2761        require_align(a->rd, s->lmul) &&
2762        require_vm(a->vm, a->rd)) {
2763        uint32_t data = 0;
2764        TCGLabel *over = gen_new_label();
2765        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2766
2767        data = FIELD_DP32(data, VDATA, VM, a->vm);
2768        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2769        static gen_helper_gvec_2_ptr * const fns[4] = {
2770            gen_helper_vid_v_b, gen_helper_vid_v_h,
2771            gen_helper_vid_v_w, gen_helper_vid_v_d,
2772        };
2773        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2774                           cpu_env, s->vlen / 8, s->vlen / 8,
2775                           data, fns[s->sew]);
2776        mark_vs_dirty(s);
2777        gen_set_label(over);
2778        return true;
2779    }
2780    return false;
2781}
2782
2783/*
2784 *** Vector Permutation Instructions
2785 */
2786
2787/* Integer Extract Instruction */
2788
2789static void load_element(TCGv_i64 dest, TCGv_ptr base,
2790                         int ofs, int sew)
2791{
2792    switch (sew) {
2793    case MO_8:
2794        tcg_gen_ld8u_i64(dest, base, ofs);
2795        break;
2796    case MO_16:
2797        tcg_gen_ld16u_i64(dest, base, ofs);
2798        break;
2799    case MO_32:
2800        tcg_gen_ld32u_i64(dest, base, ofs);
2801        break;
2802    case MO_64:
2803        tcg_gen_ld_i64(dest, base, ofs);
2804        break;
2805    default:
2806        g_assert_not_reached();
2807        break;
2808    }
2809}
2810
2811/* offset of the idx element with base regsiter r */
2812static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2813{
2814#ifdef HOST_WORDS_BIGENDIAN
2815    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2816#else
2817    return vreg_ofs(s, r) + (idx << s->sew);
2818#endif
2819}
2820
2821/* adjust the index according to the endian */
2822static void endian_adjust(TCGv_i32 ofs, int sew)
2823{
2824#ifdef HOST_WORDS_BIGENDIAN
2825    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2826#endif
2827}
2828
2829/* Load idx >= VLMAX ? 0 : vreg[idx] */
2830static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2831                              int vreg, TCGv idx, int vlmax)
2832{
2833    TCGv_i32 ofs = tcg_temp_new_i32();
2834    TCGv_ptr base = tcg_temp_new_ptr();
2835    TCGv_i64 t_idx = tcg_temp_new_i64();
2836    TCGv_i64 t_vlmax, t_zero;
2837
2838    /*
2839     * Mask the index to the length so that we do
2840     * not produce an out-of-range load.
2841     */
2842    tcg_gen_trunc_tl_i32(ofs, idx);
2843    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2844
2845    /* Convert the index to an offset. */
2846    endian_adjust(ofs, s->sew);
2847    tcg_gen_shli_i32(ofs, ofs, s->sew);
2848
2849    /* Convert the index to a pointer. */
2850    tcg_gen_ext_i32_ptr(base, ofs);
2851    tcg_gen_add_ptr(base, base, cpu_env);
2852
2853    /* Perform the load. */
2854    load_element(dest, base,
2855                 vreg_ofs(s, vreg), s->sew);
2856    tcg_temp_free_ptr(base);
2857    tcg_temp_free_i32(ofs);
2858
2859    /* Flush out-of-range indexing to zero.  */
2860    t_vlmax = tcg_constant_i64(vlmax);
2861    t_zero = tcg_constant_i64(0);
2862    tcg_gen_extu_tl_i64(t_idx, idx);
2863
2864    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2865                        t_vlmax, dest, t_zero);
2866
2867    tcg_temp_free_i64(t_idx);
2868}
2869
2870static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2871                              int vreg, int idx)
2872{
2873    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2874}
2875
2876static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2877{
2878    TCGv_i64 tmp = tcg_temp_new_i64();
2879    TCGv dest = dest_gpr(s, a->rd);
2880
2881    if (a->rs1 == 0) {
2882        /* Special case vmv.x.s rd, vs2. */
2883        vec_element_loadi(s, tmp, a->rs2, 0);
2884    } else {
2885        /* This instruction ignores LMUL and vector register groups */
2886        int vlmax = s->vlen >> (3 + s->sew);
2887        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2888    }
2889
2890    tcg_gen_trunc_i64_tl(dest, tmp);
2891    gen_set_gpr(s, a->rd, dest);
2892
2893    tcg_temp_free_i64(tmp);
2894    return true;
2895}
2896
2897/* Integer Scalar Move Instruction */
2898
2899static void store_element(TCGv_i64 val, TCGv_ptr base,
2900                          int ofs, int sew)
2901{
2902    switch (sew) {
2903    case MO_8:
2904        tcg_gen_st8_i64(val, base, ofs);
2905        break;
2906    case MO_16:
2907        tcg_gen_st16_i64(val, base, ofs);
2908        break;
2909    case MO_32:
2910        tcg_gen_st32_i64(val, base, ofs);
2911        break;
2912    case MO_64:
2913        tcg_gen_st_i64(val, base, ofs);
2914        break;
2915    default:
2916        g_assert_not_reached();
2917        break;
2918    }
2919}
2920
2921/*
2922 * Store vreg[idx] = val.
2923 * The index must be in range of VLMAX.
2924 */
2925static void vec_element_storei(DisasContext *s, int vreg,
2926                               int idx, TCGv_i64 val)
2927{
2928    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2929}
2930
2931/* vmv.s.x vd, rs1 # vd[0] = rs1 */
2932static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
2933{
2934    if (vext_check_isa_ill(s)) {
2935        /* This instruction ignores LMUL and vector register groups */
2936        int maxsz = s->vlen >> 3;
2937        TCGv_i64 t1;
2938        TCGLabel *over = gen_new_label();
2939
2940        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2941        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
2942        if (a->rs1 == 0) {
2943            goto done;
2944        }
2945
2946        t1 = tcg_temp_new_i64();
2947        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
2948        vec_element_storei(s, a->rd, 0, t1);
2949        tcg_temp_free_i64(t1);
2950        mark_vs_dirty(s);
2951    done:
2952        gen_set_label(over);
2953        return true;
2954    }
2955    return false;
2956}
2957
2958/* Floating-Point Scalar Move Instructions */
2959static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
2960{
2961    if (!s->vill && has_ext(s, RVF) &&
2962        (s->mstatus_fs != 0) && (s->sew != 0)) {
2963        unsigned int len = 8 << s->sew;
2964
2965        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
2966        if (len < 64) {
2967            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
2968                            MAKE_64BIT_MASK(len, 64 - len));
2969        }
2970
2971        mark_fs_dirty(s);
2972        return true;
2973    }
2974    return false;
2975}
2976
2977/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2978static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
2979{
2980    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
2981        TCGv_i64 t1;
2982        /* The instructions ignore LMUL and vector register group. */
2983        uint32_t vlmax = s->vlen >> 3;
2984
2985        /* if vl == 0, skip vector register write back */
2986        TCGLabel *over = gen_new_label();
2987        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2988
2989        /* zeroed all elements */
2990        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
2991
2992        /* NaN-box f[rs1] as necessary for SEW */
2993        t1 = tcg_temp_new_i64();
2994        if (s->sew == MO_64 && !has_ext(s, RVD)) {
2995            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
2996        } else {
2997            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
2998        }
2999        vec_element_storei(s, a->rd, 0, t1);
3000        tcg_temp_free_i64(t1);
3001        mark_vs_dirty(s);
3002        gen_set_label(over);
3003        return true;
3004    }
3005    return false;
3006}
3007
3008/* Vector Slide Instructions */
3009static bool slideup_check(DisasContext *s, arg_rmrr *a)
3010{
3011    return require_rvv(s) &&
3012           vext_check_isa_ill(s) &&
3013           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
3014}
3015
3016GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
3017GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
3018GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
3019
3020static bool slidedown_check(DisasContext *s, arg_rmrr *a)
3021{
3022    return require_rvv(s) &&
3023           vext_check_isa_ill(s) &&
3024           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
3025}
3026
3027GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
3028GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
3029GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
3030
3031/* Vector Register Gather Instruction */
3032static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
3033{
3034    return require_rvv(s) &&
3035           vext_check_isa_ill(s) &&
3036           require_align(a->rd, s->lmul) &&
3037           require_align(a->rs1, s->lmul) &&
3038           require_align(a->rs2, s->lmul) &&
3039           (a->rd != a->rs2 && a->rd != a->rs1) &&
3040           require_vm(a->vm, a->rd);
3041}
3042
3043GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
3044
3045static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
3046{
3047    return require_rvv(s) &&
3048           vext_check_isa_ill(s) &&
3049           require_align(a->rd, s->lmul) &&
3050           require_align(a->rs2, s->lmul) &&
3051           (a->rd != a->rs2) &&
3052           require_vm(a->vm, a->rd);
3053}
3054
3055/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3056static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3057{
3058    if (!vrgather_vx_check(s, a)) {
3059        return false;
3060    }
3061
3062    if (a->vm && s->vl_eq_vlmax) {
3063        int vlmax = s->vlen;
3064        TCGv_i64 dest = tcg_temp_new_i64();
3065
3066        if (a->rs1 == 0) {
3067            vec_element_loadi(s, dest, a->rs2, 0);
3068        } else {
3069            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3070        }
3071
3072        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3073                             MAXSZ(s), MAXSZ(s), dest);
3074        tcg_temp_free_i64(dest);
3075        mark_vs_dirty(s);
3076    } else {
3077        static gen_helper_opivx * const fns[4] = {
3078            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3079            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3080        };
3081        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3082    }
3083    return true;
3084}
3085
3086/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3087static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3088{
3089    if (!vrgather_vx_check(s, a)) {
3090        return false;
3091    }
3092
3093    if (a->vm && s->vl_eq_vlmax) {
3094        if (a->rs1 >= s->vlen) {
3095            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
3096                                 MAXSZ(s), MAXSZ(s), 0);
3097        } else {
3098            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3099                                 endian_ofs(s, a->rs2, a->rs1),
3100                                 MAXSZ(s), MAXSZ(s));
3101        }
3102        mark_vs_dirty(s);
3103    } else {
3104        static gen_helper_opivx * const fns[4] = {
3105            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3106            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3107        };
3108        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3109                           s, IMM_ZX);
3110    }
3111    return true;
3112}
3113
3114/*
3115 * Vector Compress Instruction
3116 *
3117 * The destination vector register group cannot overlap the
3118 * source vector register group or the source mask register.
3119 */
3120static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3121{
3122    return require_rvv(s) &&
3123           vext_check_isa_ill(s) &&
3124           require_align(a->rd, s->lmul) &&
3125           require_align(a->rs2, s->lmul) &&
3126           (a->rd != a->rs2) &&
3127           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1);
3128}
3129
3130static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3131{
3132    if (vcompress_vm_check(s, a)) {
3133        uint32_t data = 0;
3134        static gen_helper_gvec_4_ptr * const fns[4] = {
3135            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3136            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3137        };
3138        TCGLabel *over = gen_new_label();
3139        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3140
3141        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3142        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3143                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3144                           cpu_env, s->vlen / 8, s->vlen / 8, data,
3145                           fns[s->sew]);
3146        mark_vs_dirty(s);
3147        gen_set_label(over);
3148        return true;
3149    }
3150    return false;
3151}
3152