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