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