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