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) &&
2002            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2003}
2004
2005static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a)
2006{
2007    /*
2008     * All Zve* extensions support all vector integer instructions,
2009     * except that the vmulh integer multiply variants
2010     * that return the high word of the product
2011     * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx)
2012     * are not included for EEW=64 in Zve64*. (Section 18.2)
2013     */
2014    return opivx_check(s, a) &&
2015           (!has_ext(s, RVV) &&
2016            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2017}
2018
2019GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
2020GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check)
2021GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check)
2022GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check)
2023GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
2024GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check)
2025GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check)
2026GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check)
2027
2028/* Vector Integer Divide Instructions */
2029GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
2030GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
2031GEN_OPIVV_TRANS(vremu_vv, opivv_check)
2032GEN_OPIVV_TRANS(vrem_vv, opivv_check)
2033GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
2034GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
2035GEN_OPIVX_TRANS(vremu_vx, opivx_check)
2036GEN_OPIVX_TRANS(vrem_vx, opivx_check)
2037
2038/* Vector Widening Integer Multiply Instructions */
2039GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
2040GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
2041GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
2042GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
2043GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
2044GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
2045
2046/* Vector Single-Width Integer Multiply-Add Instructions */
2047GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
2048GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
2049GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
2050GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
2051GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
2052GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
2053GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
2054GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
2055
2056/* Vector Widening Integer Multiply-Add Instructions */
2057GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
2058GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
2059GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
2060GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
2061GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
2062GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
2063GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
2064
2065/* Vector Integer Merge and Move Instructions */
2066static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
2067{
2068    if (require_rvv(s) &&
2069        vext_check_isa_ill(s) &&
2070        /* vmv.v.v has rs2 = 0 and vm = 1 */
2071        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
2072        if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
2073            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
2074                             vreg_ofs(s, a->rs1),
2075                             MAXSZ(s), MAXSZ(s));
2076        } else {
2077            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2078            data = FIELD_DP32(data, VDATA, VTA, s->vta);
2079            static gen_helper_gvec_2_ptr * const fns[4] = {
2080                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
2081                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
2082            };
2083            TCGLabel *over = gen_new_label();
2084            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2085            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2086
2087            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
2088                               cpu_env, s->cfg_ptr->vlen / 8,
2089                               s->cfg_ptr->vlen / 8, data,
2090                               fns[s->sew]);
2091            gen_set_label(over);
2092        }
2093        mark_vs_dirty(s);
2094        return true;
2095    }
2096    return false;
2097}
2098
2099typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
2100static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
2101{
2102    if (require_rvv(s) &&
2103        vext_check_isa_ill(s) &&
2104        /* vmv.v.x has rs2 = 0 and vm = 1 */
2105        vext_check_ss(s, a->rd, 0, 1)) {
2106        TCGv s1;
2107        TCGLabel *over = gen_new_label();
2108        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2109        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2110
2111        s1 = get_gpr(s, a->rs1, EXT_SIGN);
2112
2113        if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
2114            if (get_xl(s) == MXL_RV32 && s->sew == MO_64) {
2115                TCGv_i64 s1_i64 = tcg_temp_new_i64();
2116                tcg_gen_ext_tl_i64(s1_i64, s1);
2117                tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2118                                     MAXSZ(s), MAXSZ(s), s1_i64);
2119                tcg_temp_free_i64(s1_i64);
2120            } else {
2121                tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
2122                                    MAXSZ(s), MAXSZ(s), s1);
2123            }
2124        } else {
2125            TCGv_i32 desc;
2126            TCGv_i64 s1_i64 = tcg_temp_new_i64();
2127            TCGv_ptr dest = tcg_temp_new_ptr();
2128            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2129            data = FIELD_DP32(data, VDATA, VTA, s->vta);
2130            static gen_helper_vmv_vx * const fns[4] = {
2131                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2132                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2133            };
2134
2135            tcg_gen_ext_tl_i64(s1_i64, s1);
2136            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2137                                              s->cfg_ptr->vlen / 8, data));
2138            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2139            fns[s->sew](dest, s1_i64, cpu_env, desc);
2140
2141            tcg_temp_free_ptr(dest);
2142            tcg_temp_free_i64(s1_i64);
2143        }
2144
2145        mark_vs_dirty(s);
2146        gen_set_label(over);
2147        return true;
2148    }
2149    return false;
2150}
2151
2152static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
2153{
2154    if (require_rvv(s) &&
2155        vext_check_isa_ill(s) &&
2156        /* vmv.v.i has rs2 = 0 and vm = 1 */
2157        vext_check_ss(s, a->rd, 0, 1)) {
2158        int64_t simm = sextract64(a->rs1, 0, 5);
2159        if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
2160            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
2161                                 MAXSZ(s), MAXSZ(s), simm);
2162            mark_vs_dirty(s);
2163        } else {
2164            TCGv_i32 desc;
2165            TCGv_i64 s1;
2166            TCGv_ptr dest;
2167            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2168            data = FIELD_DP32(data, VDATA, VTA, s->vta);
2169            static gen_helper_vmv_vx * const fns[4] = {
2170                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
2171                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
2172            };
2173            TCGLabel *over = gen_new_label();
2174            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2175            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2176
2177            s1 = tcg_constant_i64(simm);
2178            dest = tcg_temp_new_ptr();
2179            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2180                                              s->cfg_ptr->vlen / 8, data));
2181            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2182            fns[s->sew](dest, s1, cpu_env, desc);
2183
2184            tcg_temp_free_ptr(dest);
2185            mark_vs_dirty(s);
2186            gen_set_label(over);
2187        }
2188        return true;
2189    }
2190    return false;
2191}
2192
2193GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
2194GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
2195GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
2196
2197/*
2198 *** Vector Fixed-Point Arithmetic Instructions
2199 */
2200
2201/* Vector Single-Width Saturating Add and Subtract */
2202GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
2203GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
2204GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
2205GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
2206GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
2207GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
2208GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
2209GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
2210GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check)
2211GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
2212
2213/* Vector Single-Width Averaging Add and Subtract */
2214GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
2215GEN_OPIVV_TRANS(vaaddu_vv, opivv_check)
2216GEN_OPIVV_TRANS(vasub_vv, opivv_check)
2217GEN_OPIVV_TRANS(vasubu_vv, opivv_check)
2218GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
2219GEN_OPIVX_TRANS(vaaddu_vx,  opivx_check)
2220GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
2221GEN_OPIVX_TRANS(vasubu_vx,  opivx_check)
2222
2223/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
2224
2225static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a)
2226{
2227    /*
2228     * All Zve* extensions support all vector fixed-point arithmetic
2229     * instructions, except that vsmul.vv and vsmul.vx are not supported
2230     * for EEW=64 in Zve64*. (Section 18.2)
2231     */
2232    return opivv_check(s, a) &&
2233           (!has_ext(s, RVV) &&
2234            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2235}
2236
2237static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a)
2238{
2239    /*
2240     * All Zve* extensions support all vector fixed-point arithmetic
2241     * instructions, except that vsmul.vv and vsmul.vx are not supported
2242     * for EEW=64 in Zve64*. (Section 18.2)
2243     */
2244    return opivx_check(s, a) &&
2245           (!has_ext(s, RVV) &&
2246            s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true);
2247}
2248
2249GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check)
2250GEN_OPIVX_TRANS(vsmul_vx,  vsmul_vx_check)
2251
2252/* Vector Single-Width Scaling Shift Instructions */
2253GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
2254GEN_OPIVV_TRANS(vssra_vv, opivv_check)
2255GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
2256GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
2257GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check)
2258GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check)
2259
2260/* Vector Narrowing Fixed-Point Clip Instructions */
2261GEN_OPIWV_NARROW_TRANS(vnclipu_wv)
2262GEN_OPIWV_NARROW_TRANS(vnclip_wv)
2263GEN_OPIWX_NARROW_TRANS(vnclipu_wx)
2264GEN_OPIWX_NARROW_TRANS(vnclip_wx)
2265GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx)
2266GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx)
2267
2268/*
2269 *** Vector Float Point Arithmetic Instructions
2270 */
2271
2272/*
2273 * As RVF-only cpus always have values NaN-boxed to 64-bits,
2274 * RVF and RVD can be treated equally.
2275 * We don't have to deal with the cases of: SEW > FLEN.
2276 *
2277 * If SEW < FLEN, check whether input fp register is a valid
2278 * NaN-boxed value, in which case the least-significant SEW bits
2279 * of the f regsiter are used, else the canonical NaN value is used.
2280 */
2281static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
2282{
2283    switch (s->sew) {
2284    case 1:
2285        gen_check_nanbox_h(out, in);
2286        break;
2287    case 2:
2288        gen_check_nanbox_s(out, in);
2289        break;
2290    case 3:
2291        tcg_gen_mov_i64(out, in);
2292        break;
2293    default:
2294        g_assert_not_reached();
2295    }
2296}
2297
2298/* Vector Single-Width Floating-Point Add/Subtract Instructions */
2299
2300/*
2301 * If the current SEW does not correspond to a supported IEEE floating-point
2302 * type, an illegal instruction exception is raised.
2303 */
2304static bool opfvv_check(DisasContext *s, arg_rmrr *a)
2305{
2306    return require_rvv(s) &&
2307           require_rvf(s) &&
2308           vext_check_isa_ill(s) &&
2309           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
2310}
2311
2312/* OPFVV without GVEC IR */
2313#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2314static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2315{                                                                  \
2316    if (CHECK(s, a)) {                                             \
2317        uint32_t data = 0;                                         \
2318        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2319            gen_helper_##NAME##_h,                                 \
2320            gen_helper_##NAME##_w,                                 \
2321            gen_helper_##NAME##_d,                                 \
2322        };                                                         \
2323        TCGLabel *over = gen_new_label();                          \
2324        gen_set_rm(s, RISCV_FRM_DYN);                              \
2325        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2326        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2327                                                                   \
2328        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2329        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2330        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
2331        data =                                                     \
2332            FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
2333        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
2334        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2335                           vreg_ofs(s, a->rs1),                    \
2336                           vreg_ofs(s, a->rs2), cpu_env,           \
2337                           s->cfg_ptr->vlen / 8,                   \
2338                           s->cfg_ptr->vlen / 8, data,             \
2339                           fns[s->sew - 1]);                       \
2340        mark_vs_dirty(s);                                          \
2341        gen_set_label(over);                                       \
2342        return true;                                               \
2343    }                                                              \
2344    return false;                                                  \
2345}
2346GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2347GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2348
2349typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2350                              TCGv_env, TCGv_i32);
2351
2352static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2353                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2354{
2355    TCGv_ptr dest, src2, mask;
2356    TCGv_i32 desc;
2357    TCGv_i64 t1;
2358
2359    TCGLabel *over = gen_new_label();
2360    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2361    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2362
2363    dest = tcg_temp_new_ptr();
2364    mask = tcg_temp_new_ptr();
2365    src2 = tcg_temp_new_ptr();
2366    desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2367                                      s->cfg_ptr->vlen / 8, data));
2368
2369    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2370    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2371    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2372
2373    /* NaN-box f[rs1] */
2374    t1 = tcg_temp_new_i64();
2375    do_nanbox(s, t1, cpu_fpr[rs1]);
2376
2377    fn(dest, mask, t1, src2, cpu_env, desc);
2378
2379    tcg_temp_free_ptr(dest);
2380    tcg_temp_free_ptr(mask);
2381    tcg_temp_free_ptr(src2);
2382    tcg_temp_free_i64(t1);
2383    mark_vs_dirty(s);
2384    gen_set_label(over);
2385    return true;
2386}
2387
2388/*
2389 * If the current SEW does not correspond to a supported IEEE floating-point
2390 * type, an illegal instruction exception is raised
2391 */
2392static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2393{
2394    return require_rvv(s) &&
2395           require_rvf(s) &&
2396           vext_check_isa_ill(s) &&
2397           vext_check_ss(s, a->rd, a->rs2, a->vm);
2398}
2399
2400/* OPFVF without GVEC IR */
2401#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2402static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2403{                                                                 \
2404    if (CHECK(s, a)) {                                            \
2405        uint32_t data = 0;                                        \
2406        static gen_helper_opfvf *const fns[3] = {                 \
2407            gen_helper_##NAME##_h,                                \
2408            gen_helper_##NAME##_w,                                \
2409            gen_helper_##NAME##_d,                                \
2410        };                                                        \
2411        gen_set_rm(s, RISCV_FRM_DYN);                             \
2412        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2413        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2414        data = FIELD_DP32(data, VDATA, VTA, s->vta);              \
2415        data = FIELD_DP32(data, VDATA, VTA_ALL_1S,                \
2416                          s->cfg_vta_all_1s);                     \
2417        data = FIELD_DP32(data, VDATA, VMA, s->vma);              \
2418        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2419                           fns[s->sew - 1], s);                   \
2420    }                                                             \
2421    return false;                                                 \
2422}
2423
2424GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2425GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2426GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2427
2428/* Vector Widening Floating-Point Add/Subtract Instructions */
2429static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2430{
2431    return require_rvv(s) &&
2432           require_scale_rvf(s) &&
2433           (s->sew != MO_8) &&
2434           vext_check_isa_ill(s) &&
2435           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2436}
2437
2438/* OPFVV with WIDEN */
2439#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2440static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2441{                                                                \
2442    if (CHECK(s, a)) {                                           \
2443        uint32_t data = 0;                                       \
2444        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2445            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2446        };                                                       \
2447        TCGLabel *over = gen_new_label();                        \
2448        gen_set_rm(s, RISCV_FRM_DYN);                            \
2449        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2450        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\
2451                                                                 \
2452        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2453        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2454        data = FIELD_DP32(data, VDATA, VTA, s->vta);             \
2455        data = FIELD_DP32(data, VDATA, VMA, s->vma);             \
2456        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2457                           vreg_ofs(s, a->rs1),                  \
2458                           vreg_ofs(s, a->rs2), cpu_env,         \
2459                           s->cfg_ptr->vlen / 8,                 \
2460                           s->cfg_ptr->vlen / 8, data,           \
2461                           fns[s->sew - 1]);                     \
2462        mark_vs_dirty(s);                                        \
2463        gen_set_label(over);                                     \
2464        return true;                                             \
2465    }                                                            \
2466    return false;                                                \
2467}
2468
2469GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2470GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2471
2472static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2473{
2474    return require_rvv(s) &&
2475           require_scale_rvf(s) &&
2476           (s->sew != MO_8) &&
2477           vext_check_isa_ill(s) &&
2478           vext_check_ds(s, a->rd, a->rs2, a->vm);
2479}
2480
2481/* OPFVF with WIDEN */
2482#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2483static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2484{                                                                \
2485    if (opfvf_widen_check(s, a)) {                               \
2486        uint32_t data = 0;                                       \
2487        static gen_helper_opfvf *const fns[2] = {                \
2488            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2489        };                                                       \
2490        gen_set_rm(s, RISCV_FRM_DYN);                            \
2491        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2492        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2493        data = FIELD_DP32(data, VDATA, VTA, s->vta);             \
2494        data = FIELD_DP32(data, VDATA, VMA, s->vma);             \
2495        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2496                           fns[s->sew - 1], s);                  \
2497    }                                                            \
2498    return false;                                                \
2499}
2500
2501GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2502GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2503
2504static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2505{
2506    return require_rvv(s) &&
2507           require_scale_rvf(s) &&
2508           (s->sew != MO_8) &&
2509           vext_check_isa_ill(s) &&
2510           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2511}
2512
2513/* WIDEN OPFVV with WIDEN */
2514#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2515static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2516{                                                                  \
2517    if (opfwv_widen_check(s, a)) {                                 \
2518        uint32_t data = 0;                                         \
2519        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2520            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2521        };                                                         \
2522        TCGLabel *over = gen_new_label();                          \
2523        gen_set_rm(s, RISCV_FRM_DYN);                              \
2524        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2525        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2526                                                                   \
2527        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2528        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2529        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
2530        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
2531        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2532                           vreg_ofs(s, a->rs1),                    \
2533                           vreg_ofs(s, a->rs2), cpu_env,           \
2534                           s->cfg_ptr->vlen / 8,                   \
2535                           s->cfg_ptr->vlen / 8, data,             \
2536                           fns[s->sew - 1]);                       \
2537        mark_vs_dirty(s);                                          \
2538        gen_set_label(over);                                       \
2539        return true;                                               \
2540    }                                                              \
2541    return false;                                                  \
2542}
2543
2544GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2545GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2546
2547static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2548{
2549    return require_rvv(s) &&
2550           require_scale_rvf(s) &&
2551           (s->sew != MO_8) &&
2552           vext_check_isa_ill(s) &&
2553           vext_check_dd(s, a->rd, a->rs2, a->vm);
2554}
2555
2556/* WIDEN OPFVF with WIDEN */
2557#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2558static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2559{                                                                \
2560    if (opfwf_widen_check(s, a)) {                               \
2561        uint32_t data = 0;                                       \
2562        static gen_helper_opfvf *const fns[2] = {                \
2563            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2564        };                                                       \
2565        gen_set_rm(s, RISCV_FRM_DYN);                            \
2566        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2567        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2568        data = FIELD_DP32(data, VDATA, VTA, s->vta);             \
2569        data = FIELD_DP32(data, VDATA, VMA, s->vma);             \
2570        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2571                           fns[s->sew - 1], s);                  \
2572    }                                                            \
2573    return false;                                                \
2574}
2575
2576GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2577GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2578
2579/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2580GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2581GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2582GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2583GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2584GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2585
2586/* Vector Widening Floating-Point Multiply */
2587GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2588GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2589
2590/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2591GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2592GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2593GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2594GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2595GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2596GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2597GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2598GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2599GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2600GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2601GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2602GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2603GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2604GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2605GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2606GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2607
2608/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2609GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2610GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2611GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2612GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2613GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2614GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2615GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2616GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2617
2618/* Vector Floating-Point Square-Root Instruction */
2619
2620/*
2621 * If the current SEW does not correspond to a supported IEEE floating-point
2622 * type, an illegal instruction exception is raised
2623 */
2624static bool opfv_check(DisasContext *s, arg_rmr *a)
2625{
2626    return require_rvv(s) &&
2627           require_rvf(s) &&
2628           vext_check_isa_ill(s) &&
2629           /* OPFV instructions ignore vs1 check */
2630           vext_check_ss(s, a->rd, a->rs2, a->vm);
2631}
2632
2633static bool do_opfv(DisasContext *s, arg_rmr *a,
2634                    gen_helper_gvec_3_ptr *fn,
2635                    bool (*checkfn)(DisasContext *, arg_rmr *),
2636                    int rm)
2637{
2638    if (checkfn(s, a)) {
2639        uint32_t data = 0;
2640        TCGLabel *over = gen_new_label();
2641        gen_set_rm_chkfrm(s, rm);
2642        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2643        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2644
2645        data = FIELD_DP32(data, VDATA, VM, a->vm);
2646        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2647        data = FIELD_DP32(data, VDATA, VTA, s->vta);
2648        data = FIELD_DP32(data, VDATA, VMA, s->vma);
2649        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2650                           vreg_ofs(s, a->rs2), cpu_env,
2651                           s->cfg_ptr->vlen / 8,
2652                           s->cfg_ptr->vlen / 8, data, fn);
2653        mark_vs_dirty(s);
2654        gen_set_label(over);
2655        return true;
2656    }
2657    return false;
2658}
2659
2660#define GEN_OPFV_TRANS(NAME, CHECK, FRM)               \
2661static bool trans_##NAME(DisasContext *s, arg_rmr *a)  \
2662{                                                      \
2663    static gen_helper_gvec_3_ptr * const fns[3] = {    \
2664        gen_helper_##NAME##_h,                         \
2665        gen_helper_##NAME##_w,                         \
2666        gen_helper_##NAME##_d                          \
2667    };                                                 \
2668    return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \
2669}
2670
2671GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN)
2672GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN)
2673GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN)
2674
2675/* Vector Floating-Point MIN/MAX Instructions */
2676GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2677GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2678GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2679GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2680
2681/* Vector Floating-Point Sign-Injection Instructions */
2682GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2683GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2684GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2685GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2686GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2687GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2688
2689/* Vector Floating-Point Compare Instructions */
2690static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2691{
2692    return require_rvv(s) &&
2693           require_rvf(s) &&
2694           vext_check_isa_ill(s) &&
2695           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2696}
2697
2698GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2699GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2700GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2701GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2702
2703static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2704{
2705    return require_rvv(s) &&
2706           require_rvf(s) &&
2707           vext_check_isa_ill(s) &&
2708           vext_check_ms(s, a->rd, a->rs2);
2709}
2710
2711GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2712GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2713GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2714GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2715GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2716GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2717
2718/* Vector Floating-Point Classify Instruction */
2719GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN)
2720
2721/* Vector Floating-Point Merge Instruction */
2722GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2723
2724static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2725{
2726    if (require_rvv(s) &&
2727        require_rvf(s) &&
2728        vext_check_isa_ill(s) &&
2729        require_align(a->rd, s->lmul)) {
2730        gen_set_rm(s, RISCV_FRM_DYN);
2731
2732        TCGv_i64 t1;
2733
2734        if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
2735            t1 = tcg_temp_new_i64();
2736            /* NaN-box f[rs1] */
2737            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2738
2739            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2740                                 MAXSZ(s), MAXSZ(s), t1);
2741            mark_vs_dirty(s);
2742        } else {
2743            TCGv_ptr dest;
2744            TCGv_i32 desc;
2745            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2746            data = FIELD_DP32(data, VDATA, VTA, s->vta);
2747            data = FIELD_DP32(data, VDATA, VMA, s->vma);
2748            static gen_helper_vmv_vx * const fns[3] = {
2749                gen_helper_vmv_v_x_h,
2750                gen_helper_vmv_v_x_w,
2751                gen_helper_vmv_v_x_d,
2752            };
2753            TCGLabel *over = gen_new_label();
2754            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2755            tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
2756
2757            t1 = tcg_temp_new_i64();
2758            /* NaN-box f[rs1] */
2759            do_nanbox(s, t1, cpu_fpr[a->rs1]);
2760
2761            dest = tcg_temp_new_ptr();
2762            desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
2763                                              s->cfg_ptr->vlen / 8, data));
2764            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2765
2766            fns[s->sew - 1](dest, t1, cpu_env, desc);
2767
2768            tcg_temp_free_ptr(dest);
2769            mark_vs_dirty(s);
2770            gen_set_label(over);
2771        }
2772        tcg_temp_free_i64(t1);
2773        return true;
2774    }
2775    return false;
2776}
2777
2778/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2779#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM)               \
2780static bool trans_##NAME(DisasContext *s, arg_rmr *a)       \
2781{                                                           \
2782    static gen_helper_gvec_3_ptr * const fns[3] = {         \
2783        gen_helper_##HELPER##_h,                            \
2784        gen_helper_##HELPER##_w,                            \
2785        gen_helper_##HELPER##_d                             \
2786    };                                                      \
2787    return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \
2788}
2789
2790GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN)
2791GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN)
2792GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN)
2793GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN)
2794/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */
2795GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ)
2796GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ)
2797
2798/* Widening Floating-Point/Integer Type-Convert Instructions */
2799
2800/*
2801 * If the current SEW does not correspond to a supported IEEE floating-point
2802 * type, an illegal instruction exception is raised
2803 */
2804static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2805{
2806    return require_rvv(s) &&
2807           vext_check_isa_ill(s) &&
2808           vext_check_ds(s, a->rd, a->rs2, a->vm);
2809}
2810
2811static bool opxfv_widen_check(DisasContext *s, arg_rmr *a)
2812{
2813    return opfv_widen_check(s, a) &&
2814           require_rvf(s);
2815}
2816
2817static bool opffv_widen_check(DisasContext *s, arg_rmr *a)
2818{
2819    return opfv_widen_check(s, a) &&
2820           require_scale_rvfmin(s) &&
2821           (s->sew != MO_8);
2822}
2823
2824#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM)             \
2825static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2826{                                                                  \
2827    if (CHECK(s, a)) {                                             \
2828        uint32_t data = 0;                                         \
2829        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2830            gen_helper_##HELPER##_h,                               \
2831            gen_helper_##HELPER##_w,                               \
2832        };                                                         \
2833        TCGLabel *over = gen_new_label();                          \
2834        gen_set_rm_chkfrm(s, FRM);                                 \
2835        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2836        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2837                                                                   \
2838        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2839        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2840        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
2841        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
2842        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2843                           vreg_ofs(s, a->rs2), cpu_env,           \
2844                           s->cfg_ptr->vlen / 8,                   \
2845                           s->cfg_ptr->vlen / 8, data,             \
2846                           fns[s->sew - 1]);                       \
2847        mark_vs_dirty(s);                                          \
2848        gen_set_label(over);                                       \
2849        return true;                                               \
2850    }                                                              \
2851    return false;                                                  \
2852}
2853
2854GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2855                     RISCV_FRM_DYN)
2856GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2857                     RISCV_FRM_DYN)
2858GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v,
2859                     RISCV_FRM_DYN)
2860/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */
2861GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v,
2862                     RISCV_FRM_RTZ)
2863GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v,
2864                     RISCV_FRM_RTZ)
2865
2866static bool opfxv_widen_check(DisasContext *s, arg_rmr *a)
2867{
2868    return require_rvv(s) &&
2869           require_scale_rvf(s) &&
2870           vext_check_isa_ill(s) &&
2871           /* OPFV widening instructions ignore vs1 check */
2872           vext_check_ds(s, a->rd, a->rs2, a->vm);
2873}
2874
2875#define GEN_OPFXV_WIDEN_TRANS(NAME)                                \
2876static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2877{                                                                  \
2878    if (opfxv_widen_check(s, a)) {                                 \
2879        uint32_t data = 0;                                         \
2880        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2881            gen_helper_##NAME##_b,                                 \
2882            gen_helper_##NAME##_h,                                 \
2883            gen_helper_##NAME##_w,                                 \
2884        };                                                         \
2885        TCGLabel *over = gen_new_label();                          \
2886        gen_set_rm(s, RISCV_FRM_DYN);                              \
2887        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2888        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2889                                                                   \
2890        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2891        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2892        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
2893        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
2894        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2895                           vreg_ofs(s, a->rs2), cpu_env,           \
2896                           s->cfg_ptr->vlen / 8,                   \
2897                           s->cfg_ptr->vlen / 8, data,             \
2898                           fns[s->sew]);                           \
2899        mark_vs_dirty(s);                                          \
2900        gen_set_label(over);                                       \
2901        return true;                                               \
2902    }                                                              \
2903    return false;                                                  \
2904}
2905
2906GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v)
2907GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v)
2908
2909/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2910
2911/*
2912 * If the current SEW does not correspond to a supported IEEE floating-point
2913 * type, an illegal instruction exception is raised
2914 */
2915static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2916{
2917    return require_rvv(s) &&
2918           vext_check_isa_ill(s) &&
2919           /* OPFV narrowing instructions ignore vs1 check */
2920           vext_check_sd(s, a->rd, a->rs2, a->vm);
2921}
2922
2923static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a)
2924{
2925    return opfv_narrow_check(s, a) &&
2926           require_rvf(s) &&
2927           (s->sew != MO_64);
2928}
2929
2930static bool opffv_narrow_check(DisasContext *s, arg_rmr *a)
2931{
2932    return opfv_narrow_check(s, a) &&
2933           require_scale_rvfmin(s) &&
2934           (s->sew != MO_8);
2935}
2936
2937static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a)
2938{
2939    return opfv_narrow_check(s, a) &&
2940           require_scale_rvf(s) &&
2941           (s->sew != MO_8);
2942}
2943
2944#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM)            \
2945static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2946{                                                                  \
2947    if (CHECK(s, a)) {                                             \
2948        uint32_t data = 0;                                         \
2949        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2950            gen_helper_##HELPER##_h,                               \
2951            gen_helper_##HELPER##_w,                               \
2952        };                                                         \
2953        TCGLabel *over = gen_new_label();                          \
2954        gen_set_rm_chkfrm(s, FRM);                                 \
2955        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2956        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
2957                                                                   \
2958        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2959        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2960        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
2961        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
2962        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2963                           vreg_ofs(s, a->rs2), cpu_env,           \
2964                           s->cfg_ptr->vlen / 8,                   \
2965                           s->cfg_ptr->vlen / 8, data,             \
2966                           fns[s->sew - 1]);                       \
2967        mark_vs_dirty(s);                                          \
2968        gen_set_label(over);                                       \
2969        return true;                                               \
2970    }                                                              \
2971    return false;                                                  \
2972}
2973
2974GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w,
2975                      RISCV_FRM_DYN)
2976GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w,
2977                      RISCV_FRM_DYN)
2978GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w,
2979                      RISCV_FRM_DYN)
2980/* Reuse the helper function from vfncvt.f.f.w */
2981GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_rod_narrow_check, vfncvt_f_f_w,
2982                      RISCV_FRM_ROD)
2983
2984static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a)
2985{
2986    return require_rvv(s) &&
2987           require_scale_rvf(s) &&
2988           vext_check_isa_ill(s) &&
2989           /* OPFV narrowing instructions ignore vs1 check */
2990           vext_check_sd(s, a->rd, a->rs2, a->vm);
2991}
2992
2993#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM)                  \
2994static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2995{                                                                  \
2996    if (opxfv_narrow_check(s, a)) {                                \
2997        uint32_t data = 0;                                         \
2998        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2999            gen_helper_##HELPER##_b,                               \
3000            gen_helper_##HELPER##_h,                               \
3001            gen_helper_##HELPER##_w,                               \
3002        };                                                         \
3003        TCGLabel *over = gen_new_label();                          \
3004        gen_set_rm_chkfrm(s, FRM);                                 \
3005        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3006        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
3007                                                                   \
3008        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
3009        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
3010        data = FIELD_DP32(data, VDATA, VTA, s->vta);               \
3011        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
3012        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
3013                           vreg_ofs(s, a->rs2), cpu_env,           \
3014                           s->cfg_ptr->vlen / 8,                   \
3015                           s->cfg_ptr->vlen / 8, data,             \
3016                           fns[s->sew]);                           \
3017        mark_vs_dirty(s);                                          \
3018        gen_set_label(over);                                       \
3019        return true;                                               \
3020    }                                                              \
3021    return false;                                                  \
3022}
3023
3024GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN)
3025GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN)
3026/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */
3027GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ)
3028GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ)
3029
3030/*
3031 *** Vector Reduction Operations
3032 */
3033/* Vector Single-Width Integer Reduction Instructions */
3034static bool reduction_check(DisasContext *s, arg_rmrr *a)
3035{
3036    return require_rvv(s) &&
3037           vext_check_isa_ill(s) &&
3038           vext_check_reduction(s, a->rs2);
3039}
3040
3041GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
3042GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
3043GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
3044GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
3045GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
3046GEN_OPIVV_TRANS(vredand_vs, reduction_check)
3047GEN_OPIVV_TRANS(vredor_vs, reduction_check)
3048GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
3049
3050/* Vector Widening Integer Reduction Instructions */
3051static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
3052{
3053    return reduction_check(s, a) && (s->sew < MO_64) &&
3054           ((s->sew + 1) <= (s->cfg_ptr->elen >> 4));
3055}
3056
3057GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
3058GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
3059
3060/* Vector Single-Width Floating-Point Reduction Instructions */
3061static bool freduction_check(DisasContext *s, arg_rmrr *a)
3062{
3063    return reduction_check(s, a) &&
3064           require_rvf(s);
3065}
3066
3067GEN_OPFVV_TRANS(vfredusum_vs, freduction_check)
3068GEN_OPFVV_TRANS(vfredosum_vs, freduction_check)
3069GEN_OPFVV_TRANS(vfredmax_vs, freduction_check)
3070GEN_OPFVV_TRANS(vfredmin_vs, freduction_check)
3071
3072/* Vector Widening Floating-Point Reduction Instructions */
3073static bool freduction_widen_check(DisasContext *s, arg_rmrr *a)
3074{
3075    return reduction_widen_check(s, a) &&
3076           require_scale_rvf(s) &&
3077           (s->sew != MO_8);
3078}
3079
3080GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check)
3081GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check)
3082
3083/*
3084 *** Vector Mask Operations
3085 */
3086
3087/* Vector Mask-Register Logical Instructions */
3088#define GEN_MM_TRANS(NAME)                                         \
3089static bool trans_##NAME(DisasContext *s, arg_r *a)                \
3090{                                                                  \
3091    if (require_rvv(s) &&                                          \
3092        vext_check_isa_ill(s)) {                                   \
3093        uint32_t data = 0;                                         \
3094        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
3095        TCGLabel *over = gen_new_label();                          \
3096        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3097        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \
3098                                                                   \
3099        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
3100        data =                                                     \
3101            FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
3102        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
3103                           vreg_ofs(s, a->rs1),                    \
3104                           vreg_ofs(s, a->rs2), cpu_env,           \
3105                           s->cfg_ptr->vlen / 8,                   \
3106                           s->cfg_ptr->vlen / 8, data, fn);        \
3107        mark_vs_dirty(s);                                          \
3108        gen_set_label(over);                                       \
3109        return true;                                               \
3110    }                                                              \
3111    return false;                                                  \
3112}
3113
3114GEN_MM_TRANS(vmand_mm)
3115GEN_MM_TRANS(vmnand_mm)
3116GEN_MM_TRANS(vmandn_mm)
3117GEN_MM_TRANS(vmxor_mm)
3118GEN_MM_TRANS(vmor_mm)
3119GEN_MM_TRANS(vmnor_mm)
3120GEN_MM_TRANS(vmorn_mm)
3121GEN_MM_TRANS(vmxnor_mm)
3122
3123/* Vector count population in mask vcpop */
3124static bool trans_vcpop_m(DisasContext *s, arg_rmr *a)
3125{
3126    if (require_rvv(s) &&
3127        vext_check_isa_ill(s) &&
3128        s->vstart == 0) {
3129        TCGv_ptr src2, mask;
3130        TCGv dst;
3131        TCGv_i32 desc;
3132        uint32_t data = 0;
3133        data = FIELD_DP32(data, VDATA, VM, a->vm);
3134        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3135
3136        mask = tcg_temp_new_ptr();
3137        src2 = tcg_temp_new_ptr();
3138        dst = dest_gpr(s, a->rd);
3139        desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
3140                                          s->cfg_ptr->vlen / 8, data));
3141
3142        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
3143        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
3144
3145        gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc);
3146        gen_set_gpr(s, a->rd, dst);
3147
3148        tcg_temp_free_ptr(mask);
3149        tcg_temp_free_ptr(src2);
3150
3151        return true;
3152    }
3153    return false;
3154}
3155
3156/* vmfirst find-first-set mask bit */
3157static bool trans_vfirst_m(DisasContext *s, arg_rmr *a)
3158{
3159    if (require_rvv(s) &&
3160        vext_check_isa_ill(s) &&
3161        s->vstart == 0) {
3162        TCGv_ptr src2, mask;
3163        TCGv dst;
3164        TCGv_i32 desc;
3165        uint32_t data = 0;
3166        data = FIELD_DP32(data, VDATA, VM, a->vm);
3167        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3168
3169        mask = tcg_temp_new_ptr();
3170        src2 = tcg_temp_new_ptr();
3171        dst = dest_gpr(s, a->rd);
3172        desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8,
3173                                          s->cfg_ptr->vlen / 8, data));
3174
3175        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
3176        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
3177
3178        gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc);
3179        gen_set_gpr(s, a->rd, dst);
3180
3181        tcg_temp_free_ptr(mask);
3182        tcg_temp_free_ptr(src2);
3183        return true;
3184    }
3185    return false;
3186}
3187
3188/* vmsbf.m set-before-first mask bit */
3189/* vmsif.m set-includ-first mask bit */
3190/* vmsof.m set-only-first mask bit */
3191#define GEN_M_TRANS(NAME)                                          \
3192static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
3193{                                                                  \
3194    if (require_rvv(s) &&                                          \
3195        vext_check_isa_ill(s) &&                                   \
3196        require_vm(a->vm, a->rd) &&                                \
3197        (a->rd != a->rs2) &&                                       \
3198        (s->vstart == 0)) {                                        \
3199        uint32_t data = 0;                                         \
3200        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
3201        TCGLabel *over = gen_new_label();                          \
3202        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
3203                                                                   \
3204        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
3205        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
3206        data =                                                     \
3207            FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\
3208        data = FIELD_DP32(data, VDATA, VMA, s->vma);               \
3209        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
3210                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
3211                           cpu_env, s->cfg_ptr->vlen / 8,          \
3212                           s->cfg_ptr->vlen / 8,                   \
3213                           data, fn);                              \
3214        mark_vs_dirty(s);                                          \
3215        gen_set_label(over);                                       \
3216        return true;                                               \
3217    }                                                              \
3218    return false;                                                  \
3219}
3220
3221GEN_M_TRANS(vmsbf_m)
3222GEN_M_TRANS(vmsif_m)
3223GEN_M_TRANS(vmsof_m)
3224
3225/*
3226 * Vector Iota Instruction
3227 *
3228 * 1. The destination register cannot overlap the source register.
3229 * 2. If masked, cannot overlap the mask register ('v0').
3230 * 3. An illegal instruction exception is raised if vstart is non-zero.
3231 */
3232static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
3233{
3234    if (require_rvv(s) &&
3235        vext_check_isa_ill(s) &&
3236        !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) &&
3237        require_vm(a->vm, a->rd) &&
3238        require_align(a->rd, s->lmul) &&
3239        (s->vstart == 0)) {
3240        uint32_t data = 0;
3241        TCGLabel *over = gen_new_label();
3242        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3243
3244        data = FIELD_DP32(data, VDATA, VM, a->vm);
3245        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3246        data = FIELD_DP32(data, VDATA, VTA, s->vta);
3247        data = FIELD_DP32(data, VDATA, VMA, s->vma);
3248        static gen_helper_gvec_3_ptr * const fns[4] = {
3249            gen_helper_viota_m_b, gen_helper_viota_m_h,
3250            gen_helper_viota_m_w, gen_helper_viota_m_d,
3251        };
3252        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3253                           vreg_ofs(s, a->rs2), cpu_env,
3254                           s->cfg_ptr->vlen / 8,
3255                           s->cfg_ptr->vlen / 8, data, fns[s->sew]);
3256        mark_vs_dirty(s);
3257        gen_set_label(over);
3258        return true;
3259    }
3260    return false;
3261}
3262
3263/* Vector Element Index Instruction */
3264static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
3265{
3266    if (require_rvv(s) &&
3267        vext_check_isa_ill(s) &&
3268        require_align(a->rd, s->lmul) &&
3269        require_vm(a->vm, a->rd)) {
3270        uint32_t data = 0;
3271        TCGLabel *over = gen_new_label();
3272        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3273        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3274
3275        data = FIELD_DP32(data, VDATA, VM, a->vm);
3276        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3277        data = FIELD_DP32(data, VDATA, VTA, s->vta);
3278        data = FIELD_DP32(data, VDATA, VMA, s->vma);
3279        static gen_helper_gvec_2_ptr * const fns[4] = {
3280            gen_helper_vid_v_b, gen_helper_vid_v_h,
3281            gen_helper_vid_v_w, gen_helper_vid_v_d,
3282        };
3283        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3284                           cpu_env, s->cfg_ptr->vlen / 8,
3285                           s->cfg_ptr->vlen / 8,
3286                           data, fns[s->sew]);
3287        mark_vs_dirty(s);
3288        gen_set_label(over);
3289        return true;
3290    }
3291    return false;
3292}
3293
3294/*
3295 *** Vector Permutation Instructions
3296 */
3297
3298static void load_element(TCGv_i64 dest, TCGv_ptr base,
3299                         int ofs, int sew, bool sign)
3300{
3301    switch (sew) {
3302    case MO_8:
3303        if (!sign) {
3304            tcg_gen_ld8u_i64(dest, base, ofs);
3305        } else {
3306            tcg_gen_ld8s_i64(dest, base, ofs);
3307        }
3308        break;
3309    case MO_16:
3310        if (!sign) {
3311            tcg_gen_ld16u_i64(dest, base, ofs);
3312        } else {
3313            tcg_gen_ld16s_i64(dest, base, ofs);
3314        }
3315        break;
3316    case MO_32:
3317        if (!sign) {
3318            tcg_gen_ld32u_i64(dest, base, ofs);
3319        } else {
3320            tcg_gen_ld32s_i64(dest, base, ofs);
3321        }
3322        break;
3323    case MO_64:
3324        tcg_gen_ld_i64(dest, base, ofs);
3325        break;
3326    default:
3327        g_assert_not_reached();
3328        break;
3329    }
3330}
3331
3332/* offset of the idx element with base regsiter r */
3333static uint32_t endian_ofs(DisasContext *s, int r, int idx)
3334{
3335#if HOST_BIG_ENDIAN
3336    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
3337#else
3338    return vreg_ofs(s, r) + (idx << s->sew);
3339#endif
3340}
3341
3342/* adjust the index according to the endian */
3343static void endian_adjust(TCGv_i32 ofs, int sew)
3344{
3345#if HOST_BIG_ENDIAN
3346    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
3347#endif
3348}
3349
3350/* Load idx >= VLMAX ? 0 : vreg[idx] */
3351static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
3352                              int vreg, TCGv idx, int vlmax)
3353{
3354    TCGv_i32 ofs = tcg_temp_new_i32();
3355    TCGv_ptr base = tcg_temp_new_ptr();
3356    TCGv_i64 t_idx = tcg_temp_new_i64();
3357    TCGv_i64 t_vlmax, t_zero;
3358
3359    /*
3360     * Mask the index to the length so that we do
3361     * not produce an out-of-range load.
3362     */
3363    tcg_gen_trunc_tl_i32(ofs, idx);
3364    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
3365
3366    /* Convert the index to an offset. */
3367    endian_adjust(ofs, s->sew);
3368    tcg_gen_shli_i32(ofs, ofs, s->sew);
3369
3370    /* Convert the index to a pointer. */
3371    tcg_gen_ext_i32_ptr(base, ofs);
3372    tcg_gen_add_ptr(base, base, cpu_env);
3373
3374    /* Perform the load. */
3375    load_element(dest, base,
3376                 vreg_ofs(s, vreg), s->sew, false);
3377    tcg_temp_free_ptr(base);
3378    tcg_temp_free_i32(ofs);
3379
3380    /* Flush out-of-range indexing to zero.  */
3381    t_vlmax = tcg_constant_i64(vlmax);
3382    t_zero = tcg_constant_i64(0);
3383    tcg_gen_extu_tl_i64(t_idx, idx);
3384
3385    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
3386                        t_vlmax, dest, t_zero);
3387
3388    tcg_temp_free_i64(t_idx);
3389}
3390
3391static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
3392                              int vreg, int idx, bool sign)
3393{
3394    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign);
3395}
3396
3397/* Integer Scalar Move Instruction */
3398
3399static void store_element(TCGv_i64 val, TCGv_ptr base,
3400                          int ofs, int sew)
3401{
3402    switch (sew) {
3403    case MO_8:
3404        tcg_gen_st8_i64(val, base, ofs);
3405        break;
3406    case MO_16:
3407        tcg_gen_st16_i64(val, base, ofs);
3408        break;
3409    case MO_32:
3410        tcg_gen_st32_i64(val, base, ofs);
3411        break;
3412    case MO_64:
3413        tcg_gen_st_i64(val, base, ofs);
3414        break;
3415    default:
3416        g_assert_not_reached();
3417        break;
3418    }
3419}
3420
3421/*
3422 * Store vreg[idx] = val.
3423 * The index must be in range of VLMAX.
3424 */
3425static void vec_element_storei(DisasContext *s, int vreg,
3426                               int idx, TCGv_i64 val)
3427{
3428    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
3429}
3430
3431/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */
3432static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a)
3433{
3434    if (require_rvv(s) &&
3435        vext_check_isa_ill(s)) {
3436        TCGv_i64 t1;
3437        TCGv dest;
3438
3439        t1 = tcg_temp_new_i64();
3440        dest = tcg_temp_new();
3441        /*
3442         * load vreg and sign-extend to 64 bits,
3443         * then truncate to XLEN bits before storing to gpr.
3444         */
3445        vec_element_loadi(s, t1, a->rs2, 0, true);
3446        tcg_gen_trunc_i64_tl(dest, t1);
3447        gen_set_gpr(s, a->rd, dest);
3448        tcg_temp_free_i64(t1);
3449        tcg_temp_free(dest);
3450
3451        return true;
3452    }
3453    return false;
3454}
3455
3456/* vmv.s.x vd, rs1 # vd[0] = rs1 */
3457static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
3458{
3459    if (require_rvv(s) &&
3460        vext_check_isa_ill(s)) {
3461        /* This instruction ignores LMUL and vector register groups */
3462        TCGv_i64 t1;
3463        TCGv s1;
3464        TCGLabel *over = gen_new_label();
3465
3466        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3467        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3468
3469        t1 = tcg_temp_new_i64();
3470
3471        /*
3472         * load gpr and sign-extend to 64 bits,
3473         * then truncate to SEW bits when storing to vreg.
3474         */
3475        s1 = get_gpr(s, a->rs1, EXT_NONE);
3476        tcg_gen_ext_tl_i64(t1, s1);
3477        vec_element_storei(s, a->rd, 0, t1);
3478        tcg_temp_free_i64(t1);
3479        mark_vs_dirty(s);
3480        gen_set_label(over);
3481        return true;
3482    }
3483    return false;
3484}
3485
3486/* Floating-Point Scalar Move Instructions */
3487static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
3488{
3489    if (require_rvv(s) &&
3490        require_rvf(s) &&
3491        vext_check_isa_ill(s)) {
3492        gen_set_rm(s, RISCV_FRM_DYN);
3493
3494        unsigned int ofs = (8 << s->sew);
3495        unsigned int len = 64 - ofs;
3496        TCGv_i64 t_nan;
3497
3498        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false);
3499        /* NaN-box f[rd] as necessary for SEW */
3500        if (len) {
3501            t_nan = tcg_constant_i64(UINT64_MAX);
3502            tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
3503                                t_nan, ofs, len);
3504        }
3505
3506        mark_fs_dirty(s);
3507        return true;
3508    }
3509    return false;
3510}
3511
3512/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
3513static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
3514{
3515    if (require_rvv(s) &&
3516        require_rvf(s) &&
3517        vext_check_isa_ill(s)) {
3518        gen_set_rm(s, RISCV_FRM_DYN);
3519
3520        /* The instructions ignore LMUL and vector register group. */
3521        TCGv_i64 t1;
3522        TCGLabel *over = gen_new_label();
3523
3524        /* if vl == 0 or vstart >= vl, skip vector register write back */
3525        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3526        tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3527
3528        /* NaN-box f[rs1] */
3529        t1 = tcg_temp_new_i64();
3530        do_nanbox(s, t1, cpu_fpr[a->rs1]);
3531
3532        vec_element_storei(s, a->rd, 0, t1);
3533        tcg_temp_free_i64(t1);
3534        mark_vs_dirty(s);
3535        gen_set_label(over);
3536        return true;
3537    }
3538    return false;
3539}
3540
3541/* Vector Slide Instructions */
3542static bool slideup_check(DisasContext *s, arg_rmrr *a)
3543{
3544    return require_rvv(s) &&
3545           vext_check_isa_ill(s) &&
3546           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
3547}
3548
3549GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
3550GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
3551GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
3552
3553static bool slidedown_check(DisasContext *s, arg_rmrr *a)
3554{
3555    return require_rvv(s) &&
3556           vext_check_isa_ill(s) &&
3557           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
3558}
3559
3560GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
3561GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
3562GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
3563
3564/* Vector Floating-Point Slide Instructions */
3565static bool fslideup_check(DisasContext *s, arg_rmrr *a)
3566{
3567    return slideup_check(s, a) &&
3568           require_rvf(s);
3569}
3570
3571static bool fslidedown_check(DisasContext *s, arg_rmrr *a)
3572{
3573    return slidedown_check(s, a) &&
3574           require_rvf(s);
3575}
3576
3577GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check)
3578GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check)
3579
3580/* Vector Register Gather Instruction */
3581static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
3582{
3583    return require_rvv(s) &&
3584           vext_check_isa_ill(s) &&
3585           require_align(a->rd, s->lmul) &&
3586           require_align(a->rs1, s->lmul) &&
3587           require_align(a->rs2, s->lmul) &&
3588           (a->rd != a->rs2 && a->rd != a->rs1) &&
3589           require_vm(a->vm, a->rd);
3590}
3591
3592static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a)
3593{
3594    int8_t emul = MO_16 - s->sew + s->lmul;
3595    return require_rvv(s) &&
3596           vext_check_isa_ill(s) &&
3597           (emul >= -3 && emul <= 3) &&
3598           require_align(a->rd, s->lmul) &&
3599           require_align(a->rs1, emul) &&
3600           require_align(a->rs2, s->lmul) &&
3601           (a->rd != a->rs2 && a->rd != a->rs1) &&
3602           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3603                          a->rs1, 1 << MAX(emul, 0)) &&
3604           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0),
3605                          a->rs2, 1 << MAX(s->lmul, 0)) &&
3606           require_vm(a->vm, a->rd);
3607}
3608
3609GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
3610GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check)
3611
3612static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
3613{
3614    return require_rvv(s) &&
3615           vext_check_isa_ill(s) &&
3616           require_align(a->rd, s->lmul) &&
3617           require_align(a->rs2, s->lmul) &&
3618           (a->rd != a->rs2) &&
3619           require_vm(a->vm, a->rd);
3620}
3621
3622/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3623static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3624{
3625    if (!vrgather_vx_check(s, a)) {
3626        return false;
3627    }
3628
3629    if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
3630        int scale = s->lmul - (s->sew + 3);
3631        int vlmax = s->cfg_ptr->vlen >> -scale;
3632        TCGv_i64 dest = tcg_temp_new_i64();
3633
3634        if (a->rs1 == 0) {
3635            vec_element_loadi(s, dest, a->rs2, 0, false);
3636        } else {
3637            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3638        }
3639
3640        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3641                             MAXSZ(s), MAXSZ(s), dest);
3642        tcg_temp_free_i64(dest);
3643        mark_vs_dirty(s);
3644    } else {
3645        static gen_helper_opivx * const fns[4] = {
3646            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3647            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3648        };
3649        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3650    }
3651    return true;
3652}
3653
3654/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3655static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3656{
3657    if (!vrgather_vx_check(s, a)) {
3658        return false;
3659    }
3660
3661    if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) {
3662        int scale = s->lmul - (s->sew + 3);
3663        int vlmax = s->cfg_ptr->vlen >> -scale;
3664        if (a->rs1 >= vlmax) {
3665            tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd),
3666                                 MAXSZ(s), MAXSZ(s), 0);
3667        } else {
3668            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3669                                 endian_ofs(s, a->rs2, a->rs1),
3670                                 MAXSZ(s), MAXSZ(s));
3671        }
3672        mark_vs_dirty(s);
3673    } else {
3674        static gen_helper_opivx * const fns[4] = {
3675            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3676            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3677        };
3678        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3679                           s, IMM_ZX);
3680    }
3681    return true;
3682}
3683
3684/*
3685 * Vector Compress Instruction
3686 *
3687 * The destination vector register group cannot overlap the
3688 * source vector register group or the source mask register.
3689 */
3690static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3691{
3692    return require_rvv(s) &&
3693           vext_check_isa_ill(s) &&
3694           require_align(a->rd, s->lmul) &&
3695           require_align(a->rs2, s->lmul) &&
3696           (a->rd != a->rs2) &&
3697           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) &&
3698           (s->vstart == 0);
3699}
3700
3701static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3702{
3703    if (vcompress_vm_check(s, a)) {
3704        uint32_t data = 0;
3705        static gen_helper_gvec_4_ptr * const fns[4] = {
3706            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3707            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3708        };
3709        TCGLabel *over = gen_new_label();
3710        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3711
3712        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3713        data = FIELD_DP32(data, VDATA, VTA, s->vta);
3714        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3715                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3716                           cpu_env, s->cfg_ptr->vlen / 8,
3717                           s->cfg_ptr->vlen / 8, data,
3718                           fns[s->sew]);
3719        mark_vs_dirty(s);
3720        gen_set_label(over);
3721        return true;
3722    }
3723    return false;
3724}
3725
3726/*
3727 * Whole Vector Register Move Instructions ignore vtype and vl setting.
3728 * Thus, we don't need to check vill bit. (Section 16.6)
3729 */
3730#define GEN_VMV_WHOLE_TRANS(NAME, LEN)                             \
3731static bool trans_##NAME(DisasContext *s, arg_##NAME * a)               \
3732{                                                                       \
3733    if (require_rvv(s) &&                                               \
3734        QEMU_IS_ALIGNED(a->rd, LEN) &&                                  \
3735        QEMU_IS_ALIGNED(a->rs2, LEN)) {                                 \
3736        uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN;                 \
3737        if (s->vstart == 0) {                                           \
3738            /* EEW = 8 */                                               \
3739            tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd),                  \
3740                             vreg_ofs(s, a->rs2), maxsz, maxsz);        \
3741            mark_vs_dirty(s);                                           \
3742        } else {                                                        \
3743            TCGLabel *over = gen_new_label();                           \
3744            tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over);  \
3745            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \
3746                               cpu_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \
3747            mark_vs_dirty(s);                                           \
3748            gen_set_label(over);                                        \
3749        }                                                               \
3750        return true;                                                    \
3751    }                                                                   \
3752    return false;                                                       \
3753}
3754
3755GEN_VMV_WHOLE_TRANS(vmv1r_v, 1)
3756GEN_VMV_WHOLE_TRANS(vmv2r_v, 2)
3757GEN_VMV_WHOLE_TRANS(vmv4r_v, 4)
3758GEN_VMV_WHOLE_TRANS(vmv8r_v, 8)
3759
3760static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div)
3761{
3762    uint8_t from = (s->sew + 3) - div;
3763    bool ret = require_rvv(s) &&
3764        (from >= 3 && from <= 8) &&
3765        (a->rd != a->rs2) &&
3766        require_align(a->rd, s->lmul) &&
3767        require_align(a->rs2, s->lmul - div) &&
3768        require_vm(a->vm, a->rd) &&
3769        require_noover(a->rd, s->lmul, a->rs2, s->lmul - div);
3770    return ret;
3771}
3772
3773static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq)
3774{
3775    uint32_t data = 0;
3776    gen_helper_gvec_3_ptr *fn;
3777    TCGLabel *over = gen_new_label();
3778    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3779    tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);
3780
3781    static gen_helper_gvec_3_ptr * const fns[6][4] = {
3782        {
3783            NULL, gen_helper_vzext_vf2_h,
3784            gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d
3785        },
3786        {
3787            NULL, NULL,
3788            gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d,
3789        },
3790        {
3791            NULL, NULL,
3792            NULL, gen_helper_vzext_vf8_d
3793        },
3794        {
3795            NULL, gen_helper_vsext_vf2_h,
3796            gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d
3797        },
3798        {
3799            NULL, NULL,
3800            gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d,
3801        },
3802        {
3803            NULL, NULL,
3804            NULL, gen_helper_vsext_vf8_d
3805        }
3806    };
3807
3808    fn = fns[seq][s->sew];
3809    if (fn == NULL) {
3810        return false;
3811    }
3812
3813    data = FIELD_DP32(data, VDATA, VM, a->vm);
3814    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3815    data = FIELD_DP32(data, VDATA, VTA, s->vta);
3816    data = FIELD_DP32(data, VDATA, VMA, s->vma);
3817
3818    tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3819                       vreg_ofs(s, a->rs2), cpu_env,
3820                       s->cfg_ptr->vlen / 8,
3821                       s->cfg_ptr->vlen / 8, data, fn);
3822
3823    mark_vs_dirty(s);
3824    gen_set_label(over);
3825    return true;
3826}
3827
3828/* Vector Integer Extension */
3829#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ)             \
3830static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
3831{                                                     \
3832    if (int_ext_check(s, a, DIV)) {                   \
3833        return int_ext_op(s, a, SEQ);                 \
3834    }                                                 \
3835    return false;                                     \
3836}
3837
3838GEN_INT_EXT_TRANS(vzext_vf2, 1, 0)
3839GEN_INT_EXT_TRANS(vzext_vf4, 2, 1)
3840GEN_INT_EXT_TRANS(vzext_vf8, 3, 2)
3841GEN_INT_EXT_TRANS(vsext_vf2, 1, 3)
3842GEN_INT_EXT_TRANS(vsext_vf4, 2, 4)
3843GEN_INT_EXT_TRANS(vsext_vf8, 3, 5)
3844