1/*
2 * RISC-V translation routines for the RVV Standard Extension.
3 *
4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "tcg/tcg-op-gvec.h"
19#include "tcg/tcg-gvec-desc.h"
20#include "internals.h"
21
22static inline bool is_overlapped(const int8_t astart, int8_t asize,
23                                 const int8_t bstart, int8_t bsize)
24{
25    const int8_t aend = astart + asize;
26    const int8_t bend = bstart + bsize;
27
28    return MAX(aend, bend) - MIN(astart, bstart) < asize + bsize;
29}
30
31static bool require_rvv(DisasContext *s)
32{
33    return s->mstatus_vs != 0;
34}
35
36static bool require_rvf(DisasContext *s)
37{
38    if (s->mstatus_fs == 0) {
39        return false;
40    }
41
42    switch (s->sew) {
43    case MO_16:
44    case MO_32:
45        return has_ext(s, RVF);
46    case MO_64:
47        return has_ext(s, RVD);
48    default:
49        return false;
50    }
51}
52
53static bool require_scale_rvf(DisasContext *s)
54{
55    if (s->mstatus_fs == 0) {
56        return false;
57    }
58
59    switch (s->sew) {
60    case MO_8:
61    case MO_16:
62        return has_ext(s, RVF);
63    case MO_32:
64        return has_ext(s, RVD);
65    default:
66        return false;
67    }
68}
69
70/* Destination vector register group cannot overlap source mask register. */
71static bool require_vm(int vm, int vd)
72{
73    return (vm != 0 || vd != 0);
74}
75
76/*
77 * Vector register should aligned with the passed-in LMUL (EMUL).
78 * If LMUL < 0, i.e. fractional LMUL, any vector register is allowed.
79 */
80static bool require_align(const int8_t val, const int8_t lmul)
81{
82    return lmul <= 0 || extract32(val, 0, lmul) == 0;
83}
84
85/*
86 * A destination vector register group can overlap a source vector
87 * register group only if one of the following holds:
88 *  1. The destination EEW equals the source EEW.
89 *  2. The destination EEW is smaller than the source EEW and the overlap
90 *     is in the lowest-numbered part of the source register group.
91 *  3. The destination EEW is greater than the source EEW, the source EMUL
92 *     is at least 1, and the overlap is in the highest-numbered part of
93 *     the destination register group.
94 * (Section 5.2)
95 *
96 * This function returns true if one of the following holds:
97 *  * Destination vector register group does not overlap a source vector
98 *    register group.
99 *  * Rule 3 met.
100 * For rule 1, overlap is allowed so this function doesn't need to be called.
101 * For rule 2, (vd == vs). Caller has to check whether: (vd != vs) before
102 * calling this function.
103 */
104static bool require_noover(const int8_t dst, const int8_t dst_lmul,
105                           const int8_t src, const int8_t src_lmul)
106{
107    int8_t dst_size = dst_lmul <= 0 ? 1 : 1 << dst_lmul;
108    int8_t src_size = src_lmul <= 0 ? 1 : 1 << src_lmul;
109
110    /* Destination EEW is greater than the source EEW, check rule 3. */
111    if (dst_size > src_size) {
112        if (dst < src &&
113            src_lmul >= 0 &&
114            is_overlapped(dst, dst_size, src, src_size) &&
115            !is_overlapped(dst, dst_size, src + src_size, src_size)) {
116            return true;
117        }
118    }
119
120    return !is_overlapped(dst, dst_size, src, src_size);
121}
122
123static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a)
124{
125    TCGv s1, s2, dst;
126
127    if (!require_rvv(ctx) || !has_ext(ctx, RVV)) {
128        return false;
129    }
130
131    s2 = get_gpr(ctx, a->rs2, EXT_ZERO);
132    dst = dest_gpr(ctx, a->rd);
133
134    /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
135    if (a->rs1 == 0) {
136        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
137        s1 = tcg_constant_tl(RV_VLEN_MAX);
138    } else {
139        s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
140    }
141    gen_helper_vsetvl(dst, cpu_env, s1, s2);
142    gen_set_gpr(ctx, a->rd, dst);
143    mark_vs_dirty(ctx);
144
145    tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
146    tcg_gen_lookup_and_goto_ptr();
147    ctx->base.is_jmp = DISAS_NORETURN;
148    return true;
149}
150
151static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a)
152{
153    TCGv s1, s2, dst;
154
155    if (!require_rvv(ctx) || !has_ext(ctx, RVV)) {
156        return false;
157    }
158
159    s2 = tcg_constant_tl(a->zimm);
160    dst = dest_gpr(ctx, a->rd);
161
162    /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
163    if (a->rs1 == 0) {
164        /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
165        s1 = tcg_constant_tl(RV_VLEN_MAX);
166    } else {
167        s1 = get_gpr(ctx, a->rs1, EXT_ZERO);
168    }
169    gen_helper_vsetvl(dst, cpu_env, s1, s2);
170    gen_set_gpr(ctx, a->rd, dst);
171    mark_vs_dirty(ctx);
172
173    gen_goto_tb(ctx, 0, ctx->pc_succ_insn);
174    ctx->base.is_jmp = DISAS_NORETURN;
175    return true;
176}
177
178/* vector register offset from env */
179static uint32_t vreg_ofs(DisasContext *s, int reg)
180{
181    return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8;
182}
183
184/* check functions */
185
186static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm)
187{
188    return require_vm(vm, vd) &&
189        require_align(vd, s->lmul) &&
190        require_align(vs, s->lmul);
191}
192
193/*
194 * Check function for vector instruction with format:
195 * single-width result and single-width sources (SEW = SEW op SEW)
196 *
197 * Rules to be checked here:
198 *   1. Destination vector register group for a masked vector
199 *      instruction cannot overlap the source mask register (v0).
200 *      (Section 5.3)
201 *   2. Destination vector register number is multiples of LMUL.
202 *      (Section 3.4.2)
203 *   3. Source (vs2, vs1) vector register number are multiples of LMUL.
204 *      (Section 3.4.2)
205 */
206static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm)
207{
208    return vext_check_ss(s, vd, vs2, vm) &&
209        require_align(vs1, s->lmul);
210}
211
212static bool vext_check_ms(DisasContext *s, int vd, int vs)
213{
214    bool ret = require_align(vs, s->lmul);
215    if (vd != vs) {
216        ret &= require_noover(vd, 0, vs, s->lmul);
217    }
218    return ret;
219}
220
221/*
222 * Check function for maskable vector instruction with format:
223 * single-width result and single-width sources (SEW = SEW op SEW)
224 *
225 * Rules to be checked here:
226 *   1. Source (vs2, vs1) vector register number are multiples of LMUL.
227 *      (Section 3.4.2)
228 *   2. Destination vector register cannot overlap a source vector
229 *      register (vs2, vs1) group.
230 *      (Section 5.2)
231 *   3. The destination vector register group for a masked vector
232 *      instruction cannot overlap the source mask register (v0),
233 *      unless the destination vector register is being written
234 *      with a mask value (e.g., comparisons) or the scalar result
235 *      of a reduction. (Section 5.3)
236 */
237static bool vext_check_mss(DisasContext *s, int vd, int vs1, int vs2)
238{
239    bool ret = vext_check_ms(s, vd, vs2) &&
240        require_align(vs1, s->lmul);
241    if (vd != vs1) {
242        ret &= require_noover(vd, 0, vs1, s->lmul);
243    }
244    return ret;
245}
246
247/*
248 * Common check function for vector widening instructions
249 * of double-width result (2*SEW).
250 *
251 * Rules to be checked here:
252 *   1. The largest vector register group used by an instruction
253 *      can not be greater than 8 vector registers (Section 5.2):
254 *      => LMUL < 8.
255 *      => SEW < 64.
256 *   2. Destination vector register number is multiples of 2 * LMUL.
257 *      (Section 3.4.2)
258 *   3. Destination vector register group for a masked vector
259 *      instruction cannot overlap the source mask register (v0).
260 *      (Section 5.3)
261 */
262static bool vext_wide_check_common(DisasContext *s, int vd, int vm)
263{
264    return (s->lmul <= 2) &&
265           (s->sew < MO_64) &&
266           require_align(vd, s->lmul + 1) &&
267           require_vm(vm, vd);
268}
269
270/*
271 * Common check function for vector narrowing instructions
272 * of single-width result (SEW) and double-width source (2*SEW).
273 *
274 * Rules to be checked here:
275 *   1. The largest vector register group used by an instruction
276 *      can not be greater than 8 vector registers (Section 5.2):
277 *      => LMUL < 8.
278 *      => SEW < 64.
279 *   2. Source vector register number is multiples of 2 * LMUL.
280 *      (Section 3.4.2)
281 *   3. Destination vector register number is multiples of LMUL.
282 *      (Section 3.4.2)
283 *   4. Destination vector register group for a masked vector
284 *      instruction cannot overlap the source mask register (v0).
285 *      (Section 5.3)
286 */
287static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2,
288                                     int vm)
289{
290    return (s->lmul <= 2) &&
291           (s->sew < MO_64) &&
292           require_align(vs2, s->lmul + 1) &&
293           require_align(vd, s->lmul) &&
294           require_vm(vm, vd);
295}
296
297static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm)
298{
299    return vext_wide_check_common(s, vd, vm) &&
300        require_align(vs, s->lmul) &&
301        require_noover(vd, s->lmul + 1, vs, s->lmul);
302}
303
304static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm)
305{
306    return vext_wide_check_common(s, vd, vm) &&
307        require_align(vs, s->lmul + 1);
308}
309
310/*
311 * Check function for vector instruction with format:
312 * double-width result and single-width sources (2*SEW = SEW op SEW)
313 *
314 * Rules to be checked here:
315 *   1. All rules in defined in widen common rules are applied.
316 *   2. Source (vs2, vs1) vector register number are multiples of LMUL.
317 *      (Section 3.4.2)
318 *   3. Destination vector register cannot overlap a source vector
319 *      register (vs2, vs1) group.
320 *      (Section 5.2)
321 */
322static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm)
323{
324    return vext_check_ds(s, vd, vs2, vm) &&
325        require_align(vs1, s->lmul) &&
326        require_noover(vd, s->lmul + 1, vs1, s->lmul);
327}
328
329/*
330 * Check function for vector instruction with format:
331 * double-width result and double-width source1 and single-width
332 * source2 (2*SEW = 2*SEW op SEW)
333 *
334 * Rules to be checked here:
335 *   1. All rules in defined in widen common rules are applied.
336 *   2. Source 1 (vs2) vector register number is multiples of 2 * LMUL.
337 *      (Section 3.4.2)
338 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
339 *      (Section 3.4.2)
340 *   4. Destination vector register cannot overlap a source vector
341 *      register (vs1) group.
342 *      (Section 5.2)
343 */
344static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm)
345{
346    return vext_check_ds(s, vd, vs1, vm) &&
347        require_align(vs2, s->lmul + 1);
348}
349
350static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm)
351{
352    bool ret = vext_narrow_check_common(s, vd, vs, vm);
353    if (vd != vs) {
354        ret &= require_noover(vd, s->lmul, vs, s->lmul + 1);
355    }
356    return ret;
357}
358
359/*
360 * Check function for vector instruction with format:
361 * single-width result and double-width source 1 and single-width
362 * source 2 (SEW = 2*SEW op SEW)
363 *
364 * Rules to be checked here:
365 *   1. All rules in defined in narrow common rules are applied.
366 *   2. Destination vector register cannot overlap a source vector
367 *      register (vs2) group.
368 *      (Section 5.2)
369 *   3. Source 2 (vs1) vector register number is multiples of LMUL.
370 *      (Section 3.4.2)
371 */
372static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm)
373{
374    return vext_check_sd(s, vd, vs2, vm) &&
375        require_align(vs1, s->lmul);
376}
377
378/*
379 * Check function for vector reduction instructions.
380 *
381 * Rules to be checked here:
382 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
383 *      (Section 3.4.2)
384 */
385static bool vext_check_reduction(DisasContext *s, int vs2)
386{
387    return require_align(vs2, s->lmul);
388}
389
390/*
391 * Check function for vector slide instructions.
392 *
393 * Rules to be checked here:
394 *   1. Source 1 (vs2) vector register number is multiples of LMUL.
395 *      (Section 3.4.2)
396 *   2. Destination vector register number is multiples of LMUL.
397 *      (Section 3.4.2)
398 *   3. Destination vector register group for a masked vector
399 *      instruction cannot overlap the source mask register (v0).
400 *      (Section 5.3)
401 *   4. The destination vector register group for vslideup, vslide1up,
402 *      vfslide1up, cannot overlap the source vector register (vs2) group.
403 *      (Section 5.2, 16.3.1, 16.3.3)
404 */
405static bool vext_check_slide(DisasContext *s, int vd, int vs2,
406                             int vm, bool is_over)
407{
408    bool ret = require_align(vs2, s->lmul) &&
409               require_align(vd, s->lmul) &&
410               require_vm(vm, vd);
411    if (is_over) {
412        ret &= (vd != vs2);
413    }
414    return ret;
415}
416
417/*
418 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
419 * So RVV is also be checked in this function.
420 */
421static bool vext_check_isa_ill(DisasContext *s)
422{
423    return !s->vill;
424}
425
426/*
427 * There are two rules check here.
428 *
429 * 1. Vector register numbers are multiples of LMUL. (Section 3.2)
430 *
431 * 2. For all widening instructions, the destination LMUL value must also be
432 *    a supported LMUL value. (Section 11.2)
433 */
434static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen)
435{
436    /*
437     * The destination vector register group results are arranged as if both
438     * SEW and LMUL were at twice their current settings. (Section 11.2).
439     */
440    int legal = widen ? 2 << s->lmul : 1 << s->lmul;
441
442    return !((s->lmul == 0x3 && widen) || (reg % legal));
443}
444
445/*
446 * There are two rules check here.
447 *
448 * 1. The destination vector register group for a masked vector instruction can
449 *    only overlap the source mask register (v0) when LMUL=1. (Section 5.3)
450 *
451 * 2. In widen instructions and some other insturctions, like vslideup.vx,
452 *    there is no need to check whether LMUL=1.
453 */
454static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm,
455    bool force)
456{
457    return (vm != 0 || vd != 0) || (!force && (s->lmul == 0));
458}
459
460/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */
461static bool vext_check_nf(DisasContext *s, uint32_t nf)
462{
463    return (1 << s->lmul) * nf <= 8;
464}
465
466/*
467 * The destination vector register group cannot overlap a source vector register
468 * group of a different element width. (Section 11.2)
469 */
470static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen)
471{
472    return ((rd >= rs + slen) || (rs >= rd + dlen));
473}
474
475/* common translation macro */
476#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK)      \
477static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\
478{                                                          \
479    if (CHECK(s, a)) {                                     \
480        return OP(s, a, SEQ);                              \
481    }                                                      \
482    return false;                                          \
483}
484
485/*
486 *** unit stride load and store
487 */
488typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv,
489                                TCGv_env, TCGv_i32);
490
491static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
492                          gen_helper_ldst_us *fn, DisasContext *s,
493                          bool is_store)
494{
495    TCGv_ptr dest, mask;
496    TCGv base;
497    TCGv_i32 desc;
498
499    TCGLabel *over = gen_new_label();
500    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
501
502    dest = tcg_temp_new_ptr();
503    mask = tcg_temp_new_ptr();
504    base = get_gpr(s, rs1, EXT_NONE);
505
506    /*
507     * As simd_desc supports at most 256 bytes, and in this implementation,
508     * the max vector group length is 2048 bytes. So split it into two parts.
509     *
510     * The first part is vlen in bytes, encoded in maxsz of simd_desc.
511     * The second part is lmul, encoded in data of simd_desc.
512     */
513    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
514
515    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
516    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
517
518    fn(dest, mask, base, cpu_env, desc);
519
520    tcg_temp_free_ptr(dest);
521    tcg_temp_free_ptr(mask);
522
523    if (!is_store) {
524        mark_vs_dirty(s);
525    }
526
527    gen_set_label(over);
528    return true;
529}
530
531static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
532{
533    uint32_t data = 0;
534    gen_helper_ldst_us *fn;
535    static gen_helper_ldst_us * const fns[2][7][4] = {
536        /* masked unit stride load */
537        { { gen_helper_vlb_v_b_mask,  gen_helper_vlb_v_h_mask,
538            gen_helper_vlb_v_w_mask,  gen_helper_vlb_v_d_mask },
539          { NULL,                     gen_helper_vlh_v_h_mask,
540            gen_helper_vlh_v_w_mask,  gen_helper_vlh_v_d_mask },
541          { NULL,                     NULL,
542            gen_helper_vlw_v_w_mask,  gen_helper_vlw_v_d_mask },
543          { gen_helper_vle_v_b_mask,  gen_helper_vle_v_h_mask,
544            gen_helper_vle_v_w_mask,  gen_helper_vle_v_d_mask },
545          { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask,
546            gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask },
547          { NULL,                     gen_helper_vlhu_v_h_mask,
548            gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask },
549          { NULL,                     NULL,
550            gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } },
551        /* unmasked unit stride load */
552        { { gen_helper_vlb_v_b,  gen_helper_vlb_v_h,
553            gen_helper_vlb_v_w,  gen_helper_vlb_v_d },
554          { NULL,                gen_helper_vlh_v_h,
555            gen_helper_vlh_v_w,  gen_helper_vlh_v_d },
556          { NULL,                NULL,
557            gen_helper_vlw_v_w,  gen_helper_vlw_v_d },
558          { gen_helper_vle_v_b,  gen_helper_vle_v_h,
559            gen_helper_vle_v_w,  gen_helper_vle_v_d },
560          { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h,
561            gen_helper_vlbu_v_w, gen_helper_vlbu_v_d },
562          { NULL,                gen_helper_vlhu_v_h,
563            gen_helper_vlhu_v_w, gen_helper_vlhu_v_d },
564          { NULL,                NULL,
565            gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } }
566    };
567
568    fn =  fns[a->vm][seq][s->sew];
569    if (fn == NULL) {
570        return false;
571    }
572
573    data = FIELD_DP32(data, VDATA, VM, a->vm);
574    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
575    data = FIELD_DP32(data, VDATA, NF, a->nf);
576    return ldst_us_trans(a->rd, a->rs1, data, fn, s, false);
577}
578
579static bool ld_us_check(DisasContext *s, arg_r2nfvm* a)
580{
581    return (vext_check_isa_ill(s) &&
582            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
583            vext_check_reg(s, a->rd, false) &&
584            vext_check_nf(s, a->nf));
585}
586
587GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check)
588GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check)
589GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check)
590GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check)
591GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check)
592GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check)
593GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check)
594
595static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
596{
597    uint32_t data = 0;
598    gen_helper_ldst_us *fn;
599    static gen_helper_ldst_us * const fns[2][4][4] = {
600        /* masked unit stride load and store */
601        { { gen_helper_vsb_v_b_mask,  gen_helper_vsb_v_h_mask,
602            gen_helper_vsb_v_w_mask,  gen_helper_vsb_v_d_mask },
603          { NULL,                     gen_helper_vsh_v_h_mask,
604            gen_helper_vsh_v_w_mask,  gen_helper_vsh_v_d_mask },
605          { NULL,                     NULL,
606            gen_helper_vsw_v_w_mask,  gen_helper_vsw_v_d_mask },
607          { gen_helper_vse_v_b_mask,  gen_helper_vse_v_h_mask,
608            gen_helper_vse_v_w_mask,  gen_helper_vse_v_d_mask } },
609        /* unmasked unit stride store */
610        { { gen_helper_vsb_v_b,  gen_helper_vsb_v_h,
611            gen_helper_vsb_v_w,  gen_helper_vsb_v_d },
612          { NULL,                gen_helper_vsh_v_h,
613            gen_helper_vsh_v_w,  gen_helper_vsh_v_d },
614          { NULL,                NULL,
615            gen_helper_vsw_v_w,  gen_helper_vsw_v_d },
616          { gen_helper_vse_v_b,  gen_helper_vse_v_h,
617            gen_helper_vse_v_w,  gen_helper_vse_v_d } }
618    };
619
620    fn =  fns[a->vm][seq][s->sew];
621    if (fn == NULL) {
622        return false;
623    }
624
625    data = FIELD_DP32(data, VDATA, VM, a->vm);
626    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
627    data = FIELD_DP32(data, VDATA, NF, a->nf);
628    return ldst_us_trans(a->rd, a->rs1, data, fn, s, true);
629}
630
631static bool st_us_check(DisasContext *s, arg_r2nfvm* a)
632{
633    return (vext_check_isa_ill(s) &&
634            vext_check_reg(s, a->rd, false) &&
635            vext_check_nf(s, a->nf));
636}
637
638GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check)
639GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check)
640GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check)
641GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check)
642
643/*
644 *** stride load and store
645 */
646typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv,
647                                    TCGv, TCGv_env, TCGv_i32);
648
649static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2,
650                              uint32_t data, gen_helper_ldst_stride *fn,
651                              DisasContext *s, bool is_store)
652{
653    TCGv_ptr dest, mask;
654    TCGv base, stride;
655    TCGv_i32 desc;
656
657    TCGLabel *over = gen_new_label();
658    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
659
660    dest = tcg_temp_new_ptr();
661    mask = tcg_temp_new_ptr();
662    base = get_gpr(s, rs1, EXT_NONE);
663    stride = get_gpr(s, rs2, EXT_NONE);
664    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
665
666    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
667    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
668
669    fn(dest, mask, base, stride, cpu_env, desc);
670
671    tcg_temp_free_ptr(dest);
672    tcg_temp_free_ptr(mask);
673
674    if (!is_store) {
675        mark_vs_dirty(s);
676    }
677
678    gen_set_label(over);
679    return true;
680}
681
682static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
683{
684    uint32_t data = 0;
685    gen_helper_ldst_stride *fn;
686    static gen_helper_ldst_stride * const fns[7][4] = {
687        { gen_helper_vlsb_v_b,  gen_helper_vlsb_v_h,
688          gen_helper_vlsb_v_w,  gen_helper_vlsb_v_d },
689        { NULL,                 gen_helper_vlsh_v_h,
690          gen_helper_vlsh_v_w,  gen_helper_vlsh_v_d },
691        { NULL,                 NULL,
692          gen_helper_vlsw_v_w,  gen_helper_vlsw_v_d },
693        { gen_helper_vlse_v_b,  gen_helper_vlse_v_h,
694          gen_helper_vlse_v_w,  gen_helper_vlse_v_d },
695        { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h,
696          gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d },
697        { NULL,                 gen_helper_vlshu_v_h,
698          gen_helper_vlshu_v_w, gen_helper_vlshu_v_d },
699        { NULL,                 NULL,
700          gen_helper_vlswu_v_w, gen_helper_vlswu_v_d },
701    };
702
703    fn =  fns[seq][s->sew];
704    if (fn == NULL) {
705        return false;
706    }
707
708    data = FIELD_DP32(data, VDATA, VM, a->vm);
709    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
710    data = FIELD_DP32(data, VDATA, NF, a->nf);
711    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
712}
713
714static bool ld_stride_check(DisasContext *s, arg_rnfvm* a)
715{
716    return (vext_check_isa_ill(s) &&
717            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
718            vext_check_reg(s, a->rd, false) &&
719            vext_check_nf(s, a->nf));
720}
721
722GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check)
723GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check)
724GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check)
725GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check)
726GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check)
727GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check)
728GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check)
729
730static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
731{
732    uint32_t data = 0;
733    gen_helper_ldst_stride *fn;
734    static gen_helper_ldst_stride * const fns[4][4] = {
735        /* masked stride store */
736        { gen_helper_vssb_v_b,  gen_helper_vssb_v_h,
737          gen_helper_vssb_v_w,  gen_helper_vssb_v_d },
738        { NULL,                 gen_helper_vssh_v_h,
739          gen_helper_vssh_v_w,  gen_helper_vssh_v_d },
740        { NULL,                 NULL,
741          gen_helper_vssw_v_w,  gen_helper_vssw_v_d },
742        { gen_helper_vsse_v_b,  gen_helper_vsse_v_h,
743          gen_helper_vsse_v_w,  gen_helper_vsse_v_d }
744    };
745
746    data = FIELD_DP32(data, VDATA, VM, a->vm);
747    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
748    data = FIELD_DP32(data, VDATA, NF, a->nf);
749    fn =  fns[seq][s->sew];
750    if (fn == NULL) {
751        return false;
752    }
753
754    return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
755}
756
757static bool st_stride_check(DisasContext *s, arg_rnfvm* a)
758{
759    return (vext_check_isa_ill(s) &&
760            vext_check_reg(s, a->rd, false) &&
761            vext_check_nf(s, a->nf));
762}
763
764GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check)
765GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check)
766GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check)
767GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check)
768
769/*
770 *** index load and store
771 */
772typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv,
773                                   TCGv_ptr, TCGv_env, TCGv_i32);
774
775static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
776                             uint32_t data, gen_helper_ldst_index *fn,
777                             DisasContext *s, bool is_store)
778{
779    TCGv_ptr dest, mask, index;
780    TCGv base;
781    TCGv_i32 desc;
782
783    TCGLabel *over = gen_new_label();
784    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
785
786    dest = tcg_temp_new_ptr();
787    mask = tcg_temp_new_ptr();
788    index = tcg_temp_new_ptr();
789    base = get_gpr(s, rs1, EXT_NONE);
790    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
791
792    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
793    tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2));
794    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
795
796    fn(dest, mask, base, index, cpu_env, desc);
797
798    tcg_temp_free_ptr(dest);
799    tcg_temp_free_ptr(mask);
800    tcg_temp_free_ptr(index);
801
802    if (!is_store) {
803        mark_vs_dirty(s);
804    }
805
806    gen_set_label(over);
807    return true;
808}
809
810static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
811{
812    uint32_t data = 0;
813    gen_helper_ldst_index *fn;
814    static gen_helper_ldst_index * const fns[7][4] = {
815        { gen_helper_vlxb_v_b,  gen_helper_vlxb_v_h,
816          gen_helper_vlxb_v_w,  gen_helper_vlxb_v_d },
817        { NULL,                 gen_helper_vlxh_v_h,
818          gen_helper_vlxh_v_w,  gen_helper_vlxh_v_d },
819        { NULL,                 NULL,
820          gen_helper_vlxw_v_w,  gen_helper_vlxw_v_d },
821        { gen_helper_vlxe_v_b,  gen_helper_vlxe_v_h,
822          gen_helper_vlxe_v_w,  gen_helper_vlxe_v_d },
823        { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h,
824          gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d },
825        { NULL,                 gen_helper_vlxhu_v_h,
826          gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d },
827        { NULL,                 NULL,
828          gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d },
829    };
830
831    fn =  fns[seq][s->sew];
832    if (fn == NULL) {
833        return false;
834    }
835
836    data = FIELD_DP32(data, VDATA, VM, a->vm);
837    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
838    data = FIELD_DP32(data, VDATA, NF, a->nf);
839    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false);
840}
841
842/*
843 * For vector indexed segment loads, the destination vector register
844 * groups cannot overlap the source vector register group (specified by
845 * `vs2`), else an illegal instruction exception is raised.
846 */
847static bool ld_index_check(DisasContext *s, arg_rnfvm* a)
848{
849    return (vext_check_isa_ill(s) &&
850            vext_check_overlap_mask(s, a->rd, a->vm, false) &&
851            vext_check_reg(s, a->rd, false) &&
852            vext_check_reg(s, a->rs2, false) &&
853            vext_check_nf(s, a->nf) &&
854            ((a->nf == 1) ||
855             vext_check_overlap_group(a->rd, a->nf << s->lmul,
856                                      a->rs2, 1 << s->lmul)));
857}
858
859GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check)
860GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check)
861GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check)
862GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check)
863GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check)
864GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check)
865GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check)
866
867static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq)
868{
869    uint32_t data = 0;
870    gen_helper_ldst_index *fn;
871    static gen_helper_ldst_index * const fns[4][4] = {
872        { gen_helper_vsxb_v_b,  gen_helper_vsxb_v_h,
873          gen_helper_vsxb_v_w,  gen_helper_vsxb_v_d },
874        { NULL,                 gen_helper_vsxh_v_h,
875          gen_helper_vsxh_v_w,  gen_helper_vsxh_v_d },
876        { NULL,                 NULL,
877          gen_helper_vsxw_v_w,  gen_helper_vsxw_v_d },
878        { gen_helper_vsxe_v_b,  gen_helper_vsxe_v_h,
879          gen_helper_vsxe_v_w,  gen_helper_vsxe_v_d }
880    };
881
882    fn =  fns[seq][s->sew];
883    if (fn == NULL) {
884        return false;
885    }
886
887    data = FIELD_DP32(data, VDATA, VM, a->vm);
888    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
889    data = FIELD_DP32(data, VDATA, NF, a->nf);
890    return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true);
891}
892
893static bool st_index_check(DisasContext *s, arg_rnfvm* a)
894{
895    return (vext_check_isa_ill(s) &&
896            vext_check_reg(s, a->rd, false) &&
897            vext_check_reg(s, a->rs2, false) &&
898            vext_check_nf(s, a->nf));
899}
900
901GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check)
902GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check)
903GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check)
904GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check)
905
906/*
907 *** unit stride fault-only-first load
908 */
909static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
910                       gen_helper_ldst_us *fn, DisasContext *s)
911{
912    TCGv_ptr dest, mask;
913    TCGv base;
914    TCGv_i32 desc;
915
916    TCGLabel *over = gen_new_label();
917    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
918
919    dest = tcg_temp_new_ptr();
920    mask = tcg_temp_new_ptr();
921    base = get_gpr(s, rs1, EXT_NONE);
922    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
923
924    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
925    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
926
927    fn(dest, mask, base, cpu_env, desc);
928
929    tcg_temp_free_ptr(dest);
930    tcg_temp_free_ptr(mask);
931    mark_vs_dirty(s);
932    gen_set_label(over);
933    return true;
934}
935
936static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq)
937{
938    uint32_t data = 0;
939    gen_helper_ldst_us *fn;
940    static gen_helper_ldst_us * const fns[7][4] = {
941        { gen_helper_vlbff_v_b,  gen_helper_vlbff_v_h,
942          gen_helper_vlbff_v_w,  gen_helper_vlbff_v_d },
943        { NULL,                  gen_helper_vlhff_v_h,
944          gen_helper_vlhff_v_w,  gen_helper_vlhff_v_d },
945        { NULL,                  NULL,
946          gen_helper_vlwff_v_w,  gen_helper_vlwff_v_d },
947        { gen_helper_vleff_v_b,  gen_helper_vleff_v_h,
948          gen_helper_vleff_v_w,  gen_helper_vleff_v_d },
949        { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h,
950          gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d },
951        { NULL,                  gen_helper_vlhuff_v_h,
952          gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d },
953        { NULL,                  NULL,
954          gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d }
955    };
956
957    fn =  fns[seq][s->sew];
958    if (fn == NULL) {
959        return false;
960    }
961
962    data = FIELD_DP32(data, VDATA, VM, a->vm);
963    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
964    data = FIELD_DP32(data, VDATA, NF, a->nf);
965    return ldff_trans(a->rd, a->rs1, data, fn, s);
966}
967
968GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check)
969GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check)
970GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check)
971GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check)
972GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check)
973GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check)
974GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check)
975
976/*
977 *** Vector Integer Arithmetic Instructions
978 */
979#define MAXSZ(s) (s->vlen >> (3 - s->lmul))
980
981static bool opivv_check(DisasContext *s, arg_rmrr *a)
982{
983    return require_rvv(s) &&
984           vext_check_isa_ill(s) &&
985           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
986}
987
988typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
989                        uint32_t, uint32_t, uint32_t);
990
991static inline bool
992do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn,
993              gen_helper_gvec_4_ptr *fn)
994{
995    TCGLabel *over = gen_new_label();
996    if (!opivv_check(s, a)) {
997        return false;
998    }
999
1000    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1001
1002    if (a->vm && s->vl_eq_vlmax) {
1003        gvec_fn(s->sew, vreg_ofs(s, a->rd),
1004                vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1),
1005                MAXSZ(s), MAXSZ(s));
1006    } else {
1007        uint32_t data = 0;
1008
1009        data = FIELD_DP32(data, VDATA, VM, a->vm);
1010        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1011        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1012                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
1013                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1014    }
1015    mark_vs_dirty(s);
1016    gen_set_label(over);
1017    return true;
1018}
1019
1020/* OPIVV with GVEC IR */
1021#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
1022static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1023{                                                                  \
1024    static gen_helper_gvec_4_ptr * const fns[4] = {                \
1025        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1026        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1027    };                                                             \
1028    return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1029}
1030
1031GEN_OPIVV_GVEC_TRANS(vadd_vv, add)
1032GEN_OPIVV_GVEC_TRANS(vsub_vv, sub)
1033
1034typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr,
1035                              TCGv_env, TCGv_i32);
1036
1037static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
1038                        gen_helper_opivx *fn, DisasContext *s)
1039{
1040    TCGv_ptr dest, src2, mask;
1041    TCGv src1;
1042    TCGv_i32 desc;
1043    uint32_t data = 0;
1044
1045    TCGLabel *over = gen_new_label();
1046    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1047
1048    dest = tcg_temp_new_ptr();
1049    mask = tcg_temp_new_ptr();
1050    src2 = tcg_temp_new_ptr();
1051    src1 = get_gpr(s, rs1, EXT_NONE);
1052
1053    data = FIELD_DP32(data, VDATA, VM, vm);
1054    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1055    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1056
1057    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1058    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1059    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1060
1061    fn(dest, mask, src1, src2, cpu_env, desc);
1062
1063    tcg_temp_free_ptr(dest);
1064    tcg_temp_free_ptr(mask);
1065    tcg_temp_free_ptr(src2);
1066    mark_vs_dirty(s);
1067    gen_set_label(over);
1068    return true;
1069}
1070
1071static bool opivx_check(DisasContext *s, arg_rmrr *a)
1072{
1073    return require_rvv(s) &&
1074           vext_check_isa_ill(s) &&
1075           vext_check_ss(s, a->rd, a->rs2, a->vm);
1076}
1077
1078typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64,
1079                         uint32_t, uint32_t);
1080
1081static inline bool
1082do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn,
1083              gen_helper_opivx *fn)
1084{
1085    if (!opivx_check(s, a)) {
1086        return false;
1087    }
1088
1089    if (a->vm && s->vl_eq_vlmax) {
1090        TCGv_i64 src1 = tcg_temp_new_i64();
1091
1092        tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN));
1093        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1094                src1, MAXSZ(s), MAXSZ(s));
1095
1096        tcg_temp_free_i64(src1);
1097        mark_vs_dirty(s);
1098        return true;
1099    }
1100    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1101}
1102
1103/* OPIVX with GVEC IR */
1104#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
1105static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1106{                                                                  \
1107    static gen_helper_opivx * const fns[4] = {                     \
1108        gen_helper_##NAME##_b, gen_helper_##NAME##_h,              \
1109        gen_helper_##NAME##_w, gen_helper_##NAME##_d,              \
1110    };                                                             \
1111    return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);   \
1112}
1113
1114GEN_OPIVX_GVEC_TRANS(vadd_vx, adds)
1115GEN_OPIVX_GVEC_TRANS(vsub_vx, subs)
1116
1117static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1118{
1119    tcg_gen_vec_sub8_i64(d, b, a);
1120}
1121
1122static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
1123{
1124    tcg_gen_vec_sub16_i64(d, b, a);
1125}
1126
1127static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
1128{
1129    tcg_gen_sub_i32(ret, arg2, arg1);
1130}
1131
1132static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
1133{
1134    tcg_gen_sub_i64(ret, arg2, arg1);
1135}
1136
1137static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
1138{
1139    tcg_gen_sub_vec(vece, r, b, a);
1140}
1141
1142static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
1143                               TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
1144{
1145    static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
1146    static const GVecGen2s rsub_op[4] = {
1147        { .fni8 = gen_vec_rsub8_i64,
1148          .fniv = gen_rsub_vec,
1149          .fno = gen_helper_vec_rsubs8,
1150          .opt_opc = vecop_list,
1151          .vece = MO_8 },
1152        { .fni8 = gen_vec_rsub16_i64,
1153          .fniv = gen_rsub_vec,
1154          .fno = gen_helper_vec_rsubs16,
1155          .opt_opc = vecop_list,
1156          .vece = MO_16 },
1157        { .fni4 = gen_rsub_i32,
1158          .fniv = gen_rsub_vec,
1159          .fno = gen_helper_vec_rsubs32,
1160          .opt_opc = vecop_list,
1161          .vece = MO_32 },
1162        { .fni8 = gen_rsub_i64,
1163          .fniv = gen_rsub_vec,
1164          .fno = gen_helper_vec_rsubs64,
1165          .opt_opc = vecop_list,
1166          .prefer_i64 = TCG_TARGET_REG_BITS == 64,
1167          .vece = MO_64 },
1168    };
1169
1170    tcg_debug_assert(vece <= MO_64);
1171    tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]);
1172}
1173
1174GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs)
1175
1176typedef enum {
1177    IMM_ZX,         /* Zero-extended */
1178    IMM_SX,         /* Sign-extended */
1179    IMM_TRUNC_SEW,  /* Truncate to log(SEW) bits */
1180    IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */
1181} imm_mode_t;
1182
1183static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode)
1184{
1185    switch (imm_mode) {
1186    case IMM_ZX:
1187        return extract64(imm, 0, 5);
1188    case IMM_SX:
1189        return sextract64(imm, 0, 5);
1190    case IMM_TRUNC_SEW:
1191        return extract64(imm, 0, s->sew + 3);
1192    case IMM_TRUNC_2SEW:
1193        return extract64(imm, 0, s->sew + 4);
1194    default:
1195        g_assert_not_reached();
1196    }
1197}
1198
1199static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm,
1200                        gen_helper_opivx *fn, DisasContext *s,
1201                        imm_mode_t imm_mode)
1202{
1203    TCGv_ptr dest, src2, mask;
1204    TCGv src1;
1205    TCGv_i32 desc;
1206    uint32_t data = 0;
1207
1208    TCGLabel *over = gen_new_label();
1209    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1210
1211    dest = tcg_temp_new_ptr();
1212    mask = tcg_temp_new_ptr();
1213    src2 = tcg_temp_new_ptr();
1214    src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode));
1215
1216    data = FIELD_DP32(data, VDATA, VM, vm);
1217    data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1218    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1219
1220    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
1221    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
1222    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
1223
1224    fn(dest, mask, src1, src2, cpu_env, desc);
1225
1226    tcg_temp_free_ptr(dest);
1227    tcg_temp_free_ptr(mask);
1228    tcg_temp_free_ptr(src2);
1229    mark_vs_dirty(s);
1230    gen_set_label(over);
1231    return true;
1232}
1233
1234typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1235                         uint32_t, uint32_t);
1236
1237static inline bool
1238do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn,
1239              gen_helper_opivx *fn, imm_mode_t imm_mode)
1240{
1241    if (!opivx_check(s, a)) {
1242        return false;
1243    }
1244
1245    if (a->vm && s->vl_eq_vlmax) {
1246        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1247                extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s));
1248        mark_vs_dirty(s);
1249        return true;
1250    }
1251    return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode);
1252}
1253
1254/* OPIVI with GVEC IR */
1255#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \
1256static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1257{                                                                  \
1258    static gen_helper_opivx * const fns[4] = {                     \
1259        gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,            \
1260        gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,            \
1261    };                                                             \
1262    return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF,                 \
1263                         fns[s->sew], IMM_MODE);                   \
1264}
1265
1266GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi)
1267
1268static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs,
1269                               int64_t c, uint32_t oprsz, uint32_t maxsz)
1270{
1271    TCGv_i64 tmp = tcg_constant_i64(c);
1272    tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz);
1273}
1274
1275GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi)
1276
1277/* Vector Widening Integer Add/Subtract */
1278
1279/* OPIVV with WIDEN */
1280static bool opivv_widen_check(DisasContext *s, arg_rmrr *a)
1281{
1282    return require_rvv(s) &&
1283           vext_check_isa_ill(s) &&
1284           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
1285}
1286
1287static bool do_opivv_widen(DisasContext *s, arg_rmrr *a,
1288                           gen_helper_gvec_4_ptr *fn,
1289                           bool (*checkfn)(DisasContext *, arg_rmrr *))
1290{
1291    if (checkfn(s, a)) {
1292        uint32_t data = 0;
1293        TCGLabel *over = gen_new_label();
1294        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1295
1296        data = FIELD_DP32(data, VDATA, VM, a->vm);
1297        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1298        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1299                           vreg_ofs(s, a->rs1),
1300                           vreg_ofs(s, a->rs2),
1301                           cpu_env, s->vlen / 8, s->vlen / 8,
1302                           data, fn);
1303        mark_vs_dirty(s);
1304        gen_set_label(over);
1305        return true;
1306    }
1307    return false;
1308}
1309
1310#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1311static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1312{                                                            \
1313    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1314        gen_helper_##NAME##_b,                               \
1315        gen_helper_##NAME##_h,                               \
1316        gen_helper_##NAME##_w                                \
1317    };                                                       \
1318    return do_opivv_widen(s, a, fns[s->sew], CHECK);         \
1319}
1320
1321GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check)
1322GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check)
1323GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check)
1324GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check)
1325
1326/* OPIVX with WIDEN */
1327static bool opivx_widen_check(DisasContext *s, arg_rmrr *a)
1328{
1329    return require_rvv(s) &&
1330           vext_check_isa_ill(s) &&
1331           vext_check_ds(s, a->rd, a->rs2, a->vm);
1332}
1333
1334static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
1335                           gen_helper_opivx *fn)
1336{
1337    if (opivx_widen_check(s, a)) {
1338        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1339    }
1340    return false;
1341}
1342
1343#define GEN_OPIVX_WIDEN_TRANS(NAME) \
1344static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1345{                                                            \
1346    static gen_helper_opivx * const fns[3] = {               \
1347        gen_helper_##NAME##_b,                               \
1348        gen_helper_##NAME##_h,                               \
1349        gen_helper_##NAME##_w                                \
1350    };                                                       \
1351    return do_opivx_widen(s, a, fns[s->sew]);                \
1352}
1353
1354GEN_OPIVX_WIDEN_TRANS(vwaddu_vx)
1355GEN_OPIVX_WIDEN_TRANS(vwadd_vx)
1356GEN_OPIVX_WIDEN_TRANS(vwsubu_vx)
1357GEN_OPIVX_WIDEN_TRANS(vwsub_vx)
1358
1359/* WIDEN OPIVV with WIDEN */
1360static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a)
1361{
1362    return require_rvv(s) &&
1363           vext_check_isa_ill(s) &&
1364           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
1365}
1366
1367static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a,
1368                           gen_helper_gvec_4_ptr *fn)
1369{
1370    if (opiwv_widen_check(s, a)) {
1371        uint32_t data = 0;
1372        TCGLabel *over = gen_new_label();
1373        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1374
1375        data = FIELD_DP32(data, VDATA, VM, a->vm);
1376        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
1377        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
1378                           vreg_ofs(s, a->rs1),
1379                           vreg_ofs(s, a->rs2),
1380                           cpu_env, s->vlen / 8, s->vlen / 8, data, fn);
1381        mark_vs_dirty(s);
1382        gen_set_label(over);
1383        return true;
1384    }
1385    return false;
1386}
1387
1388#define GEN_OPIWV_WIDEN_TRANS(NAME) \
1389static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1390{                                                            \
1391    static gen_helper_gvec_4_ptr * const fns[3] = {          \
1392        gen_helper_##NAME##_b,                               \
1393        gen_helper_##NAME##_h,                               \
1394        gen_helper_##NAME##_w                                \
1395    };                                                       \
1396    return do_opiwv_widen(s, a, fns[s->sew]);                \
1397}
1398
1399GEN_OPIWV_WIDEN_TRANS(vwaddu_wv)
1400GEN_OPIWV_WIDEN_TRANS(vwadd_wv)
1401GEN_OPIWV_WIDEN_TRANS(vwsubu_wv)
1402GEN_OPIWV_WIDEN_TRANS(vwsub_wv)
1403
1404/* WIDEN OPIVX with WIDEN */
1405static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a)
1406{
1407    return require_rvv(s) &&
1408           vext_check_isa_ill(s) &&
1409           vext_check_dd(s, a->rd, a->rs2, a->vm);
1410}
1411
1412static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a,
1413                           gen_helper_opivx *fn)
1414{
1415    if (opiwx_widen_check(s, a)) {
1416        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1417    }
1418    return false;
1419}
1420
1421#define GEN_OPIWX_WIDEN_TRANS(NAME) \
1422static bool trans_##NAME(DisasContext *s, arg_rmrr *a)       \
1423{                                                            \
1424    static gen_helper_opivx * const fns[3] = {               \
1425        gen_helper_##NAME##_b,                               \
1426        gen_helper_##NAME##_h,                               \
1427        gen_helper_##NAME##_w                                \
1428    };                                                       \
1429    return do_opiwx_widen(s, a, fns[s->sew]);                \
1430}
1431
1432GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
1433GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
1434GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
1435GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
1436
1437/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1438/* OPIVV without GVEC IR */
1439#define GEN_OPIVV_TRANS(NAME, CHECK)                               \
1440static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1441{                                                                  \
1442    if (CHECK(s, a)) {                                             \
1443        uint32_t data = 0;                                         \
1444        static gen_helper_gvec_4_ptr * const fns[4] = {            \
1445            gen_helper_##NAME##_b, gen_helper_##NAME##_h,          \
1446            gen_helper_##NAME##_w, gen_helper_##NAME##_d,          \
1447        };                                                         \
1448        TCGLabel *over = gen_new_label();                          \
1449        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1450                                                                   \
1451        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1452        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1453        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1454                           vreg_ofs(s, a->rs1),                    \
1455                           vreg_ofs(s, a->rs2), cpu_env,           \
1456                           s->vlen / 8, s->vlen / 8, data,         \
1457                           fns[s->sew]);                           \
1458        mark_vs_dirty(s);                                          \
1459        gen_set_label(over);                                       \
1460        return true;                                               \
1461    }                                                              \
1462    return false;                                                  \
1463}
1464
1465/*
1466 * For vadc and vsbc, an illegal instruction exception is raised if the
1467 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1468 */
1469static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
1470{
1471    return require_rvv(s) &&
1472           vext_check_isa_ill(s) &&
1473           (a->rd != 0) &&
1474           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
1475}
1476
1477GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
1478GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
1479
1480/*
1481 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1482 * destination vector register overlaps a source vector register group.
1483 */
1484static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
1485{
1486    return require_rvv(s) &&
1487           vext_check_isa_ill(s) &&
1488           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1489}
1490
1491GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
1492GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
1493
1494static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
1495{
1496    return require_rvv(s) &&
1497           vext_check_isa_ill(s) &&
1498           (a->rd != 0) &&
1499           vext_check_ss(s, a->rd, a->rs2, a->vm);
1500}
1501
1502/* OPIVX without GVEC IR */
1503#define GEN_OPIVX_TRANS(NAME, CHECK)                                     \
1504static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1505{                                                                        \
1506    if (CHECK(s, a)) {                                                   \
1507        static gen_helper_opivx * const fns[4] = {                       \
1508            gen_helper_##NAME##_b, gen_helper_##NAME##_h,                \
1509            gen_helper_##NAME##_w, gen_helper_##NAME##_d,                \
1510        };                                                               \
1511                                                                         \
1512        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1513    }                                                                    \
1514    return false;                                                        \
1515}
1516
1517GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
1518GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
1519
1520static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
1521{
1522    return require_rvv(s) &&
1523           vext_check_isa_ill(s) &&
1524           vext_check_ms(s, a->rd, a->rs2);
1525}
1526
1527GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
1528GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
1529
1530/* OPIVI without GVEC IR */
1531#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK)                    \
1532static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1533{                                                                        \
1534    if (CHECK(s, a)) {                                                   \
1535        static gen_helper_opivx * const fns[4] = {                       \
1536            gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h,              \
1537            gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d,              \
1538        };                                                               \
1539        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1540                           fns[s->sew], s, IMM_MODE);                    \
1541    }                                                                    \
1542    return false;                                                        \
1543}
1544
1545GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check)
1546GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check)
1547
1548/* Vector Bitwise Logical Instructions */
1549GEN_OPIVV_GVEC_TRANS(vand_vv, and)
1550GEN_OPIVV_GVEC_TRANS(vor_vv,  or)
1551GEN_OPIVV_GVEC_TRANS(vxor_vv, xor)
1552GEN_OPIVX_GVEC_TRANS(vand_vx, ands)
1553GEN_OPIVX_GVEC_TRANS(vor_vx,  ors)
1554GEN_OPIVX_GVEC_TRANS(vxor_vx, xors)
1555GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi)
1556GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx,  ori)
1557GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori)
1558
1559/* Vector Single-Width Bit Shift Instructions */
1560GEN_OPIVV_GVEC_TRANS(vsll_vv,  shlv)
1561GEN_OPIVV_GVEC_TRANS(vsrl_vv,  shrv)
1562GEN_OPIVV_GVEC_TRANS(vsra_vv,  sarv)
1563
1564typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32,
1565                           uint32_t, uint32_t);
1566
1567static inline bool
1568do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn,
1569                    gen_helper_opivx *fn)
1570{
1571    if (!opivx_check(s, a)) {
1572        return false;
1573    }
1574
1575    if (a->vm && s->vl_eq_vlmax) {
1576        TCGv_i32 src1 = tcg_temp_new_i32();
1577
1578        tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE));
1579        tcg_gen_extract_i32(src1, src1, 0, s->sew + 3);
1580        gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2),
1581                src1, MAXSZ(s), MAXSZ(s));
1582
1583        tcg_temp_free_i32(src1);
1584        mark_vs_dirty(s);
1585        return true;
1586    }
1587    return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
1588}
1589
1590#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1591static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                    \
1592{                                                                         \
1593    static gen_helper_opivx * const fns[4] = {                            \
1594        gen_helper_##NAME##_b, gen_helper_##NAME##_h,                     \
1595        gen_helper_##NAME##_w, gen_helper_##NAME##_d,                     \
1596    };                                                                    \
1597                                                                          \
1598    return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]);    \
1599}
1600
1601GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx,  shls)
1602GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx,  shrs)
1603GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx,  sars)
1604
1605GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_ZX, vsll_vx, shli)
1606GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_ZX, vsrl_vx, shri)
1607GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_ZX, vsra_vx, sari)
1608
1609/* Vector Narrowing Integer Right Shift Instructions */
1610static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a)
1611{
1612    return require_rvv(s) &&
1613           vext_check_isa_ill(s) &&
1614           vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm);
1615}
1616
1617/* OPIVV with NARROW */
1618#define GEN_OPIVV_NARROW_TRANS(NAME)                               \
1619static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
1620{                                                                  \
1621    if (opivv_narrow_check(s, a)) {                                \
1622        uint32_t data = 0;                                         \
1623        static gen_helper_gvec_4_ptr * const fns[3] = {            \
1624            gen_helper_##NAME##_b,                                 \
1625            gen_helper_##NAME##_h,                                 \
1626            gen_helper_##NAME##_w,                                 \
1627        };                                                         \
1628        TCGLabel *over = gen_new_label();                          \
1629        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
1630                                                                   \
1631        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
1632        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
1633        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
1634                           vreg_ofs(s, a->rs1),                    \
1635                           vreg_ofs(s, a->rs2), cpu_env,           \
1636                           s->vlen / 8, s->vlen / 8, data,         \
1637                           fns[s->sew]);                           \
1638        mark_vs_dirty(s);                                          \
1639        gen_set_label(over);                                       \
1640        return true;                                               \
1641    }                                                              \
1642    return false;                                                  \
1643}
1644GEN_OPIVV_NARROW_TRANS(vnsra_vv)
1645GEN_OPIVV_NARROW_TRANS(vnsrl_vv)
1646
1647static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a)
1648{
1649    return require_rvv(s) &&
1650           vext_check_isa_ill(s) &&
1651           vext_check_sd(s, a->rd, a->rs2, a->vm);
1652}
1653
1654/* OPIVX with NARROW */
1655#define GEN_OPIVX_NARROW_TRANS(NAME)                                     \
1656static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1657{                                                                        \
1658    if (opivx_narrow_check(s, a)) {                                      \
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 opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1665    }                                                                    \
1666    return false;                                                        \
1667}
1668
1669GEN_OPIVX_NARROW_TRANS(vnsra_vx)
1670GEN_OPIVX_NARROW_TRANS(vnsrl_vx)
1671
1672/* OPIVI with NARROW */
1673#define GEN_OPIVI_NARROW_TRANS(NAME, IMM_MODE, OPIVX)                    \
1674static bool trans_##NAME(DisasContext *s, arg_rmrr *a)                   \
1675{                                                                        \
1676    if (opivx_narrow_check(s, a)) {                                      \
1677        static gen_helper_opivx * const fns[3] = {                       \
1678            gen_helper_##OPIVX##_b,                                      \
1679            gen_helper_##OPIVX##_h,                                      \
1680            gen_helper_##OPIVX##_w,                                      \
1681        };                                                               \
1682        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm,                 \
1683                           fns[s->sew], s, IMM_MODE);                    \
1684    }                                                                    \
1685    return false;                                                        \
1686}
1687
1688GEN_OPIVI_NARROW_TRANS(vnsra_vi, IMM_ZX, vnsra_vx)
1689GEN_OPIVI_NARROW_TRANS(vnsrl_vi, IMM_ZX, vnsrl_vx)
1690
1691/* Vector Integer Comparison Instructions */
1692/*
1693 * For all comparison instructions, an illegal instruction exception is raised
1694 * if the destination vector register overlaps a source vector register group
1695 * and LMUL > 1.
1696 */
1697static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a)
1698{
1699    return require_rvv(s) &&
1700           vext_check_isa_ill(s) &&
1701           vext_check_mss(s, a->rd, a->rs1, a->rs2);
1702}
1703
1704GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check)
1705GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check)
1706GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check)
1707GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check)
1708GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check)
1709GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check)
1710
1711static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a)
1712{
1713    return require_rvv(s) &&
1714           vext_check_isa_ill(s) &&
1715           vext_check_ms(s, a->rd, a->rs2);
1716}
1717
1718GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check)
1719GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check)
1720GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check)
1721GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check)
1722GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check)
1723GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check)
1724GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check)
1725GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check)
1726
1727GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check)
1728GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check)
1729GEN_OPIVI_TRANS(vmsleu_vi, IMM_ZX, vmsleu_vx, opivx_cmp_check)
1730GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check)
1731GEN_OPIVI_TRANS(vmsgtu_vi, IMM_ZX, vmsgtu_vx, opivx_cmp_check)
1732GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check)
1733
1734/* Vector Integer Min/Max Instructions */
1735GEN_OPIVV_GVEC_TRANS(vminu_vv, umin)
1736GEN_OPIVV_GVEC_TRANS(vmin_vv,  smin)
1737GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax)
1738GEN_OPIVV_GVEC_TRANS(vmax_vv,  smax)
1739GEN_OPIVX_TRANS(vminu_vx, opivx_check)
1740GEN_OPIVX_TRANS(vmin_vx,  opivx_check)
1741GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
1742GEN_OPIVX_TRANS(vmax_vx,  opivx_check)
1743
1744/* Vector Single-Width Integer Multiply Instructions */
1745GEN_OPIVV_GVEC_TRANS(vmul_vv,  mul)
1746GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
1747GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
1748GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
1749GEN_OPIVX_GVEC_TRANS(vmul_vx,  muls)
1750GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
1751GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
1752GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
1753
1754/* Vector Integer Divide Instructions */
1755GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
1756GEN_OPIVV_TRANS(vdiv_vv, opivv_check)
1757GEN_OPIVV_TRANS(vremu_vv, opivv_check)
1758GEN_OPIVV_TRANS(vrem_vv, opivv_check)
1759GEN_OPIVX_TRANS(vdivu_vx, opivx_check)
1760GEN_OPIVX_TRANS(vdiv_vx, opivx_check)
1761GEN_OPIVX_TRANS(vremu_vx, opivx_check)
1762GEN_OPIVX_TRANS(vrem_vx, opivx_check)
1763
1764/* Vector Widening Integer Multiply Instructions */
1765GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check)
1766GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check)
1767GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check)
1768GEN_OPIVX_WIDEN_TRANS(vwmul_vx)
1769GEN_OPIVX_WIDEN_TRANS(vwmulu_vx)
1770GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx)
1771
1772/* Vector Single-Width Integer Multiply-Add Instructions */
1773GEN_OPIVV_TRANS(vmacc_vv, opivv_check)
1774GEN_OPIVV_TRANS(vnmsac_vv, opivv_check)
1775GEN_OPIVV_TRANS(vmadd_vv, opivv_check)
1776GEN_OPIVV_TRANS(vnmsub_vv, opivv_check)
1777GEN_OPIVX_TRANS(vmacc_vx, opivx_check)
1778GEN_OPIVX_TRANS(vnmsac_vx, opivx_check)
1779GEN_OPIVX_TRANS(vmadd_vx, opivx_check)
1780GEN_OPIVX_TRANS(vnmsub_vx, opivx_check)
1781
1782/* Vector Widening Integer Multiply-Add Instructions */
1783GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check)
1784GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check)
1785GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check)
1786GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx)
1787GEN_OPIVX_WIDEN_TRANS(vwmacc_vx)
1788GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx)
1789GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx)
1790
1791/* Vector Integer Merge and Move Instructions */
1792static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a)
1793{
1794    if (require_rvv(s) &&
1795        vext_check_isa_ill(s) &&
1796        /* vmv.v.v has rs2 = 0 and vm = 1 */
1797        vext_check_sss(s, a->rd, a->rs1, 0, 1)) {
1798        if (s->vl_eq_vlmax) {
1799            tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd),
1800                             vreg_ofs(s, a->rs1),
1801                             MAXSZ(s), MAXSZ(s));
1802        } else {
1803            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1804            static gen_helper_gvec_2_ptr * const fns[4] = {
1805                gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h,
1806                gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d,
1807            };
1808            TCGLabel *over = gen_new_label();
1809            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1810
1811            tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1),
1812                               cpu_env, s->vlen / 8, s->vlen / 8, data,
1813                               fns[s->sew]);
1814            gen_set_label(over);
1815        }
1816        mark_vs_dirty(s);
1817        return true;
1818    }
1819    return false;
1820}
1821
1822typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32);
1823static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a)
1824{
1825    if (require_rvv(s) &&
1826        vext_check_isa_ill(s) &&
1827        /* vmv.v.x has rs2 = 0 and vm = 1 */
1828        vext_check_ss(s, a->rd, 0, 1)) {
1829        TCGv s1;
1830        TCGLabel *over = gen_new_label();
1831        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1832
1833        s1 = get_gpr(s, a->rs1, EXT_SIGN);
1834
1835        if (s->vl_eq_vlmax) {
1836            tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd),
1837                                MAXSZ(s), MAXSZ(s), s1);
1838        } else {
1839            TCGv_i32 desc;
1840            TCGv_i64 s1_i64 = tcg_temp_new_i64();
1841            TCGv_ptr dest = tcg_temp_new_ptr();
1842            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1843            static gen_helper_vmv_vx * const fns[4] = {
1844                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1845                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1846            };
1847
1848            tcg_gen_ext_tl_i64(s1_i64, s1);
1849            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1850            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1851            fns[s->sew](dest, s1_i64, cpu_env, desc);
1852
1853            tcg_temp_free_ptr(dest);
1854            tcg_temp_free_i64(s1_i64);
1855        }
1856
1857        mark_vs_dirty(s);
1858        gen_set_label(over);
1859        return true;
1860    }
1861    return false;
1862}
1863
1864static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a)
1865{
1866    if (require_rvv(s) &&
1867        vext_check_isa_ill(s) &&
1868        /* vmv.v.i has rs2 = 0 and vm = 1 */
1869        vext_check_ss(s, a->rd, 0, 1)) {
1870        int64_t simm = sextract64(a->rs1, 0, 5);
1871        if (s->vl_eq_vlmax) {
1872            tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd),
1873                                 MAXSZ(s), MAXSZ(s), simm);
1874            mark_vs_dirty(s);
1875        } else {
1876            TCGv_i32 desc;
1877            TCGv_i64 s1;
1878            TCGv_ptr dest;
1879            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
1880            static gen_helper_vmv_vx * const fns[4] = {
1881                gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h,
1882                gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d,
1883            };
1884            TCGLabel *over = gen_new_label();
1885            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
1886
1887            s1 = tcg_constant_i64(simm);
1888            dest = tcg_temp_new_ptr();
1889            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
1890            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
1891            fns[s->sew](dest, s1, cpu_env, desc);
1892
1893            tcg_temp_free_ptr(dest);
1894            mark_vs_dirty(s);
1895            gen_set_label(over);
1896        }
1897        return true;
1898    }
1899    return false;
1900}
1901
1902GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check)
1903GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check)
1904GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check)
1905
1906/*
1907 *** Vector Fixed-Point Arithmetic Instructions
1908 */
1909
1910/* Vector Single-Width Saturating Add and Subtract */
1911GEN_OPIVV_TRANS(vsaddu_vv, opivv_check)
1912GEN_OPIVV_TRANS(vsadd_vv,  opivv_check)
1913GEN_OPIVV_TRANS(vssubu_vv, opivv_check)
1914GEN_OPIVV_TRANS(vssub_vv,  opivv_check)
1915GEN_OPIVX_TRANS(vsaddu_vx,  opivx_check)
1916GEN_OPIVX_TRANS(vsadd_vx,  opivx_check)
1917GEN_OPIVX_TRANS(vssubu_vx,  opivx_check)
1918GEN_OPIVX_TRANS(vssub_vx,  opivx_check)
1919GEN_OPIVI_TRANS(vsaddu_vi, IMM_ZX, vsaddu_vx, opivx_check)
1920GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check)
1921
1922/* Vector Single-Width Averaging Add and Subtract */
1923GEN_OPIVV_TRANS(vaadd_vv, opivv_check)
1924GEN_OPIVV_TRANS(vasub_vv, opivv_check)
1925GEN_OPIVX_TRANS(vaadd_vx,  opivx_check)
1926GEN_OPIVX_TRANS(vasub_vx,  opivx_check)
1927GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check)
1928
1929/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1930GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
1931GEN_OPIVX_TRANS(vsmul_vx,  opivx_check)
1932
1933/* Vector Widening Saturating Scaled Multiply-Add */
1934GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check)
1935GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check)
1936GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check)
1937GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx)
1938GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx)
1939GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx)
1940GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx)
1941
1942/* Vector Single-Width Scaling Shift Instructions */
1943GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
1944GEN_OPIVV_TRANS(vssra_vv, opivv_check)
1945GEN_OPIVX_TRANS(vssrl_vx,  opivx_check)
1946GEN_OPIVX_TRANS(vssra_vx,  opivx_check)
1947GEN_OPIVI_TRANS(vssrl_vi, IMM_ZX, vssrl_vx, opivx_check)
1948GEN_OPIVI_TRANS(vssra_vi, IMM_SX, vssra_vx, opivx_check)
1949
1950/* Vector Narrowing Fixed-Point Clip Instructions */
1951GEN_OPIVV_NARROW_TRANS(vnclipu_vv)
1952GEN_OPIVV_NARROW_TRANS(vnclip_vv)
1953GEN_OPIVX_NARROW_TRANS(vnclipu_vx)
1954GEN_OPIVX_NARROW_TRANS(vnclip_vx)
1955GEN_OPIVI_NARROW_TRANS(vnclipu_vi, IMM_ZX, vnclipu_vx)
1956GEN_OPIVI_NARROW_TRANS(vnclip_vi, IMM_ZX, vnclip_vx)
1957
1958/*
1959 *** Vector Float Point Arithmetic Instructions
1960 */
1961
1962/*
1963 * As RVF-only cpus always have values NaN-boxed to 64-bits,
1964 * RVF and RVD can be treated equally.
1965 * We don't have to deal with the cases of: SEW > FLEN.
1966 *
1967 * If SEW < FLEN, check whether input fp register is a valid
1968 * NaN-boxed value, in which case the least-significant SEW bits
1969 * of the f regsiter are used, else the canonical NaN value is used.
1970 */
1971static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
1972{
1973    switch (s->sew) {
1974    case 1:
1975        gen_check_nanbox_h(out, in);
1976        break;
1977    case 2:
1978        gen_check_nanbox_s(out, in);
1979        break;
1980    case 3:
1981        tcg_gen_mov_i64(out, in);
1982        break;
1983    default:
1984        g_assert_not_reached();
1985    }
1986}
1987
1988/* Vector Single-Width Floating-Point Add/Subtract Instructions */
1989
1990/*
1991 * If the current SEW does not correspond to a supported IEEE floating-point
1992 * type, an illegal instruction exception is raised.
1993 */
1994static bool opfvv_check(DisasContext *s, arg_rmrr *a)
1995{
1996    return require_rvv(s) &&
1997           require_rvf(s) &&
1998           vext_check_isa_ill(s) &&
1999           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
2000}
2001
2002/* OPFVV without GVEC IR */
2003#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2004static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2005{                                                                  \
2006    if (CHECK(s, a)) {                                             \
2007        uint32_t data = 0;                                         \
2008        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2009            gen_helper_##NAME##_h,                                 \
2010            gen_helper_##NAME##_w,                                 \
2011            gen_helper_##NAME##_d,                                 \
2012        };                                                         \
2013        TCGLabel *over = gen_new_label();                          \
2014        gen_set_rm(s, 7);                                          \
2015        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2016                                                                   \
2017        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2018        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2019        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2020                           vreg_ofs(s, a->rs1),                    \
2021                           vreg_ofs(s, a->rs2), cpu_env,           \
2022                           s->vlen / 8, s->vlen / 8, data,         \
2023                           fns[s->sew - 1]);                       \
2024        mark_vs_dirty(s);                                          \
2025        gen_set_label(over);                                       \
2026        return true;                                               \
2027    }                                                              \
2028    return false;                                                  \
2029}
2030GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2031GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2032
2033typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2034                              TCGv_env, TCGv_i32);
2035
2036static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2037                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2038{
2039    TCGv_ptr dest, src2, mask;
2040    TCGv_i32 desc;
2041    TCGv_i64 t1;
2042
2043    TCGLabel *over = gen_new_label();
2044    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2045
2046    dest = tcg_temp_new_ptr();
2047    mask = tcg_temp_new_ptr();
2048    src2 = tcg_temp_new_ptr();
2049    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2050
2051    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2052    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2053    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2054
2055    /* NaN-box f[rs1] */
2056    t1 = tcg_temp_new_i64();
2057    do_nanbox(s, t1, cpu_fpr[rs1]);
2058
2059    fn(dest, mask, t1, src2, cpu_env, desc);
2060
2061    tcg_temp_free_ptr(dest);
2062    tcg_temp_free_ptr(mask);
2063    tcg_temp_free_ptr(src2);
2064    tcg_temp_free_i64(t1);
2065    mark_vs_dirty(s);
2066    gen_set_label(over);
2067    return true;
2068}
2069
2070/*
2071 * If the current SEW does not correspond to a supported IEEE floating-point
2072 * type, an illegal instruction exception is raised
2073 */
2074static bool opfvf_check(DisasContext *s, arg_rmrr *a)
2075{
2076    return require_rvv(s) &&
2077           require_rvf(s) &&
2078           vext_check_isa_ill(s) &&
2079           vext_check_ss(s, a->rd, a->rs2, a->vm);
2080}
2081
2082/* OPFVF without GVEC IR */
2083#define GEN_OPFVF_TRANS(NAME, CHECK)                              \
2084static bool trans_##NAME(DisasContext *s, arg_rmrr *a)            \
2085{                                                                 \
2086    if (CHECK(s, a)) {                                            \
2087        uint32_t data = 0;                                        \
2088        static gen_helper_opfvf *const fns[3] = {                 \
2089            gen_helper_##NAME##_h,                                \
2090            gen_helper_##NAME##_w,                                \
2091            gen_helper_##NAME##_d,                                \
2092        };                                                        \
2093        gen_set_rm(s, 7);                                         \
2094        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2095        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2096        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2097                           fns[s->sew - 1], s);                   \
2098    }                                                             \
2099    return false;                                                 \
2100}
2101
2102GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2103GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2104GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2105
2106/* Vector Widening Floating-Point Add/Subtract Instructions */
2107static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2108{
2109    return require_rvv(s) &&
2110           require_rvf(s) &&
2111           vext_check_isa_ill(s) &&
2112           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2113}
2114
2115/* OPFVV with WIDEN */
2116#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2117static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2118{                                                                \
2119    if (CHECK(s, a)) {                                           \
2120        uint32_t data = 0;                                       \
2121        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2122            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2123        };                                                       \
2124        TCGLabel *over = gen_new_label();                        \
2125        gen_set_rm(s, 7);                                        \
2126        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2127                                                                 \
2128        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2129        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2130        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2131                           vreg_ofs(s, a->rs1),                  \
2132                           vreg_ofs(s, a->rs2), cpu_env,         \
2133                           s->vlen / 8, s->vlen / 8, data,       \
2134                           fns[s->sew - 1]);                     \
2135        mark_vs_dirty(s);                                        \
2136        gen_set_label(over);                                     \
2137        return true;                                             \
2138    }                                                            \
2139    return false;                                                \
2140}
2141
2142GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2143GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2144
2145static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2146{
2147    return require_rvv(s) &&
2148           require_rvf(s) &&
2149           vext_check_isa_ill(s) &&
2150           vext_check_ds(s, a->rd, a->rs2, a->vm);
2151}
2152
2153/* OPFVF with WIDEN */
2154#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2155static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2156{                                                                \
2157    if (opfvf_widen_check(s, a)) {                               \
2158        uint32_t data = 0;                                       \
2159        static gen_helper_opfvf *const fns[2] = {                \
2160            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2161        };                                                       \
2162        gen_set_rm(s, 7);                                        \
2163        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2164        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2165        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2166                           fns[s->sew - 1], s);                  \
2167    }                                                            \
2168    return false;                                                \
2169}
2170
2171GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2172GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2173
2174static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2175{
2176    return require_rvv(s) &&
2177           require_rvf(s) &&
2178           vext_check_isa_ill(s) &&
2179           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2180}
2181
2182/* WIDEN OPFVV with WIDEN */
2183#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2184static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2185{                                                                  \
2186    if (opfwv_widen_check(s, a)) {                                 \
2187        uint32_t data = 0;                                         \
2188        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2189            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2190        };                                                         \
2191        TCGLabel *over = gen_new_label();                          \
2192        gen_set_rm(s, 7);                                          \
2193        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2194                                                                   \
2195        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2196        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2197        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2198                           vreg_ofs(s, a->rs1),                    \
2199                           vreg_ofs(s, a->rs2), cpu_env,           \
2200                           s->vlen / 8, s->vlen / 8, data,         \
2201                           fns[s->sew - 1]);                       \
2202        mark_vs_dirty(s);                                          \
2203        gen_set_label(over);                                       \
2204        return true;                                               \
2205    }                                                              \
2206    return false;                                                  \
2207}
2208
2209GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2210GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2211
2212static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2213{
2214    return require_rvv(s) &&
2215           require_rvf(s) &&
2216           vext_check_isa_ill(s) &&
2217           vext_check_dd(s, a->rd, a->rs2, a->vm);
2218}
2219
2220/* WIDEN OPFVF with WIDEN */
2221#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2222static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2223{                                                                \
2224    if (opfwf_widen_check(s, a)) {                               \
2225        uint32_t data = 0;                                       \
2226        static gen_helper_opfvf *const fns[2] = {                \
2227            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2228        };                                                       \
2229        gen_set_rm(s, 7);                                        \
2230        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2231        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2232        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2233                           fns[s->sew - 1], s);                  \
2234    }                                                            \
2235    return false;                                                \
2236}
2237
2238GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2239GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2240
2241/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2242GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2243GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2244GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2245GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2246GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2247
2248/* Vector Widening Floating-Point Multiply */
2249GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2250GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2251
2252/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2253GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2254GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2255GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2256GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2257GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2258GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2259GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2260GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2261GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2262GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2263GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2264GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2265GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2266GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2267GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2268GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2269
2270/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2271GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2272GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2273GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2274GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2275GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2276GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2277GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2278GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2279
2280/* Vector Floating-Point Square-Root Instruction */
2281
2282/*
2283 * If the current SEW does not correspond to a supported IEEE floating-point
2284 * type, an illegal instruction exception is raised
2285 */
2286static bool opfv_check(DisasContext *s, arg_rmr *a)
2287{
2288    return require_rvv(s) &&
2289           require_rvf(s) &&
2290           vext_check_isa_ill(s) &&
2291           /* OPFV instructions ignore vs1 check */
2292           vext_check_ss(s, a->rd, a->rs2, a->vm);
2293}
2294
2295#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2296static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2297{                                                                  \
2298    if (CHECK(s, a)) {                                             \
2299        uint32_t data = 0;                                         \
2300        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2301            gen_helper_##NAME##_h,                                 \
2302            gen_helper_##NAME##_w,                                 \
2303            gen_helper_##NAME##_d,                                 \
2304        };                                                         \
2305        TCGLabel *over = gen_new_label();                          \
2306        gen_set_rm(s, 7);                                          \
2307        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2308                                                                   \
2309        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2310        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2311        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2312                           vreg_ofs(s, a->rs2), cpu_env,           \
2313                           s->vlen / 8, s->vlen / 8, data,         \
2314                           fns[s->sew - 1]);                       \
2315        mark_vs_dirty(s);                                          \
2316        gen_set_label(over);                                       \
2317        return true;                                               \
2318    }                                                              \
2319    return false;                                                  \
2320}
2321
2322GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2323
2324/* Vector Floating-Point MIN/MAX Instructions */
2325GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2326GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2327GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2328GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2329
2330/* Vector Floating-Point Sign-Injection Instructions */
2331GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2332GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2333GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2334GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2335GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2336GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2337
2338/* Vector Floating-Point Compare Instructions */
2339static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2340{
2341    return require_rvv(s) &&
2342           require_rvf(s) &&
2343           vext_check_isa_ill(s) &&
2344           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2345}
2346
2347GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2348GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2349GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2350GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2351GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2352
2353static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2354{
2355    return require_rvv(s) &&
2356           require_rvf(s) &&
2357           vext_check_isa_ill(s) &&
2358           vext_check_ms(s, a->rd, a->rs2);
2359}
2360
2361GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2362GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2363GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2364GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2365GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2366GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2367GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2368
2369/* Vector Floating-Point Classify Instruction */
2370GEN_OPFV_TRANS(vfclass_v, opfv_check)
2371
2372/* Vector Floating-Point Merge Instruction */
2373GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2374
2375static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2376{
2377    if (require_rvv(s) &&
2378        require_rvf(s) &&
2379        vext_check_isa_ill(s) &&
2380        require_align(a->rd, s->lmul)) {
2381        if (s->vl_eq_vlmax) {
2382            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2383                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2384            mark_vs_dirty(s);
2385        } else {
2386            TCGv_ptr dest;
2387            TCGv_i32 desc;
2388            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2389            static gen_helper_vmv_vx * const fns[3] = {
2390                gen_helper_vmv_v_x_h,
2391                gen_helper_vmv_v_x_w,
2392                gen_helper_vmv_v_x_d,
2393            };
2394            TCGLabel *over = gen_new_label();
2395            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2396
2397            dest = tcg_temp_new_ptr();
2398            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2399            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2400            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2401
2402            tcg_temp_free_ptr(dest);
2403            mark_vs_dirty(s);
2404            gen_set_label(over);
2405        }
2406        return true;
2407    }
2408    return false;
2409}
2410
2411/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2412GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2413GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2414GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2415GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2416
2417/* Widening Floating-Point/Integer Type-Convert Instructions */
2418
2419/*
2420 * If the current SEW does not correspond to a supported IEEE floating-point
2421 * type, an illegal instruction exception is raised
2422 */
2423static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2424{
2425    return require_rvv(s) &&
2426           require_scale_rvf(s) &&
2427           (s->sew != MO_8) &&
2428           vext_check_isa_ill(s) &&
2429           vext_check_ds(s, a->rd, a->rs2, a->vm);
2430}
2431
2432#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2433static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2434{                                                                  \
2435    if (opfv_widen_check(s, a)) {                                  \
2436        uint32_t data = 0;                                         \
2437        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2438            gen_helper_##NAME##_h,                                 \
2439            gen_helper_##NAME##_w,                                 \
2440        };                                                         \
2441        TCGLabel *over = gen_new_label();                          \
2442        gen_set_rm(s, 7);                                          \
2443        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2444                                                                   \
2445        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2446        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2447        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2448                           vreg_ofs(s, a->rs2), cpu_env,           \
2449                           s->vlen / 8, s->vlen / 8, data,         \
2450                           fns[s->sew - 1]);                       \
2451        mark_vs_dirty(s);                                          \
2452        gen_set_label(over);                                       \
2453        return true;                                               \
2454    }                                                              \
2455    return false;                                                  \
2456}
2457
2458GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2459GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2460GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2461GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2462GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2463
2464/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2465
2466/*
2467 * If the current SEW does not correspond to a supported IEEE floating-point
2468 * type, an illegal instruction exception is raised
2469 */
2470static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2471{
2472    return require_rvv(s) &&
2473           require_rvf(s) &&
2474           (s->sew != MO_64) &&
2475           vext_check_isa_ill(s) &&
2476           /* OPFV narrowing instructions ignore vs1 check */
2477           vext_check_sd(s, a->rd, a->rs2, a->vm);
2478}
2479
2480#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2481static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2482{                                                                  \
2483    if (opfv_narrow_check(s, a)) {                                 \
2484        uint32_t data = 0;                                         \
2485        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2486            gen_helper_##NAME##_h,                                 \
2487            gen_helper_##NAME##_w,                                 \
2488        };                                                         \
2489        TCGLabel *over = gen_new_label();                          \
2490        gen_set_rm(s, 7);                                          \
2491        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2492                                                                   \
2493        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2494        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2495        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2496                           vreg_ofs(s, a->rs2), cpu_env,           \
2497                           s->vlen / 8, s->vlen / 8, data,         \
2498                           fns[s->sew - 1]);                       \
2499        mark_vs_dirty(s);                                          \
2500        gen_set_label(over);                                       \
2501        return true;                                               \
2502    }                                                              \
2503    return false;                                                  \
2504}
2505
2506GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2507GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2508GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2509GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2510GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2511
2512/*
2513 *** Vector Reduction Operations
2514 */
2515/* Vector Single-Width Integer Reduction Instructions */
2516static bool reduction_check(DisasContext *s, arg_rmrr *a)
2517{
2518    return require_rvv(s) &&
2519           vext_check_isa_ill(s) &&
2520           vext_check_reduction(s, a->rs2);
2521}
2522
2523GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2524GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2525GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2526GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2527GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2528GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2529GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2530GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2531
2532/* Vector Widening Integer Reduction Instructions */
2533static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
2534{
2535    return reduction_check(s, a) && (s->sew < MO_64);
2536}
2537
2538GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
2539GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
2540
2541/* Vector Single-Width Floating-Point Reduction Instructions */
2542GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2543GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2544GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2545
2546/* Vector Widening Floating-Point Reduction Instructions */
2547GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2548
2549/*
2550 *** Vector Mask Operations
2551 */
2552
2553/* Vector Mask-Register Logical Instructions */
2554#define GEN_MM_TRANS(NAME)                                         \
2555static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2556{                                                                  \
2557    if (vext_check_isa_ill(s)) {                                   \
2558        uint32_t data = 0;                                         \
2559        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2560        TCGLabel *over = gen_new_label();                          \
2561        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2562                                                                   \
2563        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2564        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2565                           vreg_ofs(s, a->rs1),                    \
2566                           vreg_ofs(s, a->rs2), cpu_env,           \
2567                           s->vlen / 8, s->vlen / 8, data, fn);    \
2568        mark_vs_dirty(s);                                          \
2569        gen_set_label(over);                                       \
2570        return true;                                               \
2571    }                                                              \
2572    return false;                                                  \
2573}
2574
2575GEN_MM_TRANS(vmand_mm)
2576GEN_MM_TRANS(vmnand_mm)
2577GEN_MM_TRANS(vmandnot_mm)
2578GEN_MM_TRANS(vmxor_mm)
2579GEN_MM_TRANS(vmor_mm)
2580GEN_MM_TRANS(vmnor_mm)
2581GEN_MM_TRANS(vmornot_mm)
2582GEN_MM_TRANS(vmxnor_mm)
2583
2584/* Vector mask population count vmpopc */
2585static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2586{
2587    if (require_rvv(s) &&
2588        vext_check_isa_ill(s)) {
2589        TCGv_ptr src2, mask;
2590        TCGv dst;
2591        TCGv_i32 desc;
2592        uint32_t data = 0;
2593        data = FIELD_DP32(data, VDATA, VM, a->vm);
2594        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2595
2596        mask = tcg_temp_new_ptr();
2597        src2 = tcg_temp_new_ptr();
2598        dst = dest_gpr(s, a->rd);
2599        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2600
2601        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2602        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2603
2604        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2605        gen_set_gpr(s, a->rd, dst);
2606
2607        tcg_temp_free_ptr(mask);
2608        tcg_temp_free_ptr(src2);
2609        return true;
2610    }
2611    return false;
2612}
2613
2614/* vmfirst find-first-set mask bit */
2615static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2616{
2617    if (require_rvv(s) &&
2618        vext_check_isa_ill(s)) {
2619        TCGv_ptr src2, mask;
2620        TCGv dst;
2621        TCGv_i32 desc;
2622        uint32_t data = 0;
2623        data = FIELD_DP32(data, VDATA, VM, a->vm);
2624        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2625
2626        mask = tcg_temp_new_ptr();
2627        src2 = tcg_temp_new_ptr();
2628        dst = dest_gpr(s, a->rd);
2629        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2630
2631        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2632        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2633
2634        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2635        gen_set_gpr(s, a->rd, dst);
2636
2637        tcg_temp_free_ptr(mask);
2638        tcg_temp_free_ptr(src2);
2639        return true;
2640    }
2641    return false;
2642}
2643
2644/* vmsbf.m set-before-first mask bit */
2645/* vmsif.m set-includ-first mask bit */
2646/* vmsof.m set-only-first mask bit */
2647#define GEN_M_TRANS(NAME)                                          \
2648static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2649{                                                                  \
2650    if (vext_check_isa_ill(s)) {                                   \
2651        uint32_t data = 0;                                         \
2652        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2653        TCGLabel *over = gen_new_label();                          \
2654        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2655                                                                   \
2656        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2657        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2658        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2659                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2660                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2661                           data, fn);                              \
2662        mark_vs_dirty(s);                                          \
2663        gen_set_label(over);                                       \
2664        return true;                                               \
2665    }                                                              \
2666    return false;                                                  \
2667}
2668
2669GEN_M_TRANS(vmsbf_m)
2670GEN_M_TRANS(vmsif_m)
2671GEN_M_TRANS(vmsof_m)
2672
2673/* Vector Iota Instruction */
2674static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2675{
2676    if (require_rvv(s) &&
2677        vext_check_isa_ill(s) &&
2678        require_noover(a->rd, s->lmul, a->rs2, 0) &&
2679        require_vm(a->vm, a->rd) &&
2680        require_align(a->rd, s->lmul)) {
2681        uint32_t data = 0;
2682        TCGLabel *over = gen_new_label();
2683        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2684
2685        data = FIELD_DP32(data, VDATA, VM, a->vm);
2686        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2687        static gen_helper_gvec_3_ptr * const fns[4] = {
2688            gen_helper_viota_m_b, gen_helper_viota_m_h,
2689            gen_helper_viota_m_w, gen_helper_viota_m_d,
2690        };
2691        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2692                           vreg_ofs(s, a->rs2), cpu_env,
2693                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2694        mark_vs_dirty(s);
2695        gen_set_label(over);
2696        return true;
2697    }
2698    return false;
2699}
2700
2701/* Vector Element Index Instruction */
2702static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2703{
2704    if (require_rvv(s) &&
2705        vext_check_isa_ill(s) &&
2706        require_align(a->rd, s->lmul) &&
2707        require_vm(a->vm, a->rd)) {
2708        uint32_t data = 0;
2709        TCGLabel *over = gen_new_label();
2710        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2711
2712        data = FIELD_DP32(data, VDATA, VM, a->vm);
2713        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2714        static gen_helper_gvec_2_ptr * const fns[4] = {
2715            gen_helper_vid_v_b, gen_helper_vid_v_h,
2716            gen_helper_vid_v_w, gen_helper_vid_v_d,
2717        };
2718        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2719                           cpu_env, s->vlen / 8, s->vlen / 8,
2720                           data, fns[s->sew]);
2721        mark_vs_dirty(s);
2722        gen_set_label(over);
2723        return true;
2724    }
2725    return false;
2726}
2727
2728/*
2729 *** Vector Permutation Instructions
2730 */
2731
2732/* Integer Extract Instruction */
2733
2734static void load_element(TCGv_i64 dest, TCGv_ptr base,
2735                         int ofs, int sew)
2736{
2737    switch (sew) {
2738    case MO_8:
2739        tcg_gen_ld8u_i64(dest, base, ofs);
2740        break;
2741    case MO_16:
2742        tcg_gen_ld16u_i64(dest, base, ofs);
2743        break;
2744    case MO_32:
2745        tcg_gen_ld32u_i64(dest, base, ofs);
2746        break;
2747    case MO_64:
2748        tcg_gen_ld_i64(dest, base, ofs);
2749        break;
2750    default:
2751        g_assert_not_reached();
2752        break;
2753    }
2754}
2755
2756/* offset of the idx element with base regsiter r */
2757static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2758{
2759#ifdef HOST_WORDS_BIGENDIAN
2760    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2761#else
2762    return vreg_ofs(s, r) + (idx << s->sew);
2763#endif
2764}
2765
2766/* adjust the index according to the endian */
2767static void endian_adjust(TCGv_i32 ofs, int sew)
2768{
2769#ifdef HOST_WORDS_BIGENDIAN
2770    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2771#endif
2772}
2773
2774/* Load idx >= VLMAX ? 0 : vreg[idx] */
2775static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2776                              int vreg, TCGv idx, int vlmax)
2777{
2778    TCGv_i32 ofs = tcg_temp_new_i32();
2779    TCGv_ptr base = tcg_temp_new_ptr();
2780    TCGv_i64 t_idx = tcg_temp_new_i64();
2781    TCGv_i64 t_vlmax, t_zero;
2782
2783    /*
2784     * Mask the index to the length so that we do
2785     * not produce an out-of-range load.
2786     */
2787    tcg_gen_trunc_tl_i32(ofs, idx);
2788    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2789
2790    /* Convert the index to an offset. */
2791    endian_adjust(ofs, s->sew);
2792    tcg_gen_shli_i32(ofs, ofs, s->sew);
2793
2794    /* Convert the index to a pointer. */
2795    tcg_gen_ext_i32_ptr(base, ofs);
2796    tcg_gen_add_ptr(base, base, cpu_env);
2797
2798    /* Perform the load. */
2799    load_element(dest, base,
2800                 vreg_ofs(s, vreg), s->sew);
2801    tcg_temp_free_ptr(base);
2802    tcg_temp_free_i32(ofs);
2803
2804    /* Flush out-of-range indexing to zero.  */
2805    t_vlmax = tcg_constant_i64(vlmax);
2806    t_zero = tcg_constant_i64(0);
2807    tcg_gen_extu_tl_i64(t_idx, idx);
2808
2809    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2810                        t_vlmax, dest, t_zero);
2811
2812    tcg_temp_free_i64(t_idx);
2813}
2814
2815static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2816                              int vreg, int idx)
2817{
2818    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2819}
2820
2821static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2822{
2823    TCGv_i64 tmp = tcg_temp_new_i64();
2824    TCGv dest = dest_gpr(s, a->rd);
2825
2826    if (a->rs1 == 0) {
2827        /* Special case vmv.x.s rd, vs2. */
2828        vec_element_loadi(s, tmp, a->rs2, 0);
2829    } else {
2830        /* This instruction ignores LMUL and vector register groups */
2831        int vlmax = s->vlen >> (3 + s->sew);
2832        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2833    }
2834
2835    tcg_gen_trunc_i64_tl(dest, tmp);
2836    gen_set_gpr(s, a->rd, dest);
2837
2838    tcg_temp_free_i64(tmp);
2839    return true;
2840}
2841
2842/* Integer Scalar Move Instruction */
2843
2844static void store_element(TCGv_i64 val, TCGv_ptr base,
2845                          int ofs, int sew)
2846{
2847    switch (sew) {
2848    case MO_8:
2849        tcg_gen_st8_i64(val, base, ofs);
2850        break;
2851    case MO_16:
2852        tcg_gen_st16_i64(val, base, ofs);
2853        break;
2854    case MO_32:
2855        tcg_gen_st32_i64(val, base, ofs);
2856        break;
2857    case MO_64:
2858        tcg_gen_st_i64(val, base, ofs);
2859        break;
2860    default:
2861        g_assert_not_reached();
2862        break;
2863    }
2864}
2865
2866/*
2867 * Store vreg[idx] = val.
2868 * The index must be in range of VLMAX.
2869 */
2870static void vec_element_storei(DisasContext *s, int vreg,
2871                               int idx, TCGv_i64 val)
2872{
2873    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2874}
2875
2876/* vmv.s.x vd, rs1 # vd[0] = rs1 */
2877static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
2878{
2879    if (vext_check_isa_ill(s)) {
2880        /* This instruction ignores LMUL and vector register groups */
2881        int maxsz = s->vlen >> 3;
2882        TCGv_i64 t1;
2883        TCGLabel *over = gen_new_label();
2884
2885        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2886        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
2887        if (a->rs1 == 0) {
2888            goto done;
2889        }
2890
2891        t1 = tcg_temp_new_i64();
2892        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
2893        vec_element_storei(s, a->rd, 0, t1);
2894        tcg_temp_free_i64(t1);
2895        mark_vs_dirty(s);
2896    done:
2897        gen_set_label(over);
2898        return true;
2899    }
2900    return false;
2901}
2902
2903/* Floating-Point Scalar Move Instructions */
2904static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
2905{
2906    if (!s->vill && has_ext(s, RVF) &&
2907        (s->mstatus_fs != 0) && (s->sew != 0)) {
2908        unsigned int len = 8 << s->sew;
2909
2910        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
2911        if (len < 64) {
2912            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
2913                            MAKE_64BIT_MASK(len, 64 - len));
2914        }
2915
2916        mark_fs_dirty(s);
2917        return true;
2918    }
2919    return false;
2920}
2921
2922/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2923static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
2924{
2925    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
2926        TCGv_i64 t1;
2927        /* The instructions ignore LMUL and vector register group. */
2928        uint32_t vlmax = s->vlen >> 3;
2929
2930        /* if vl == 0, skip vector register write back */
2931        TCGLabel *over = gen_new_label();
2932        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2933
2934        /* zeroed all elements */
2935        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
2936
2937        /* NaN-box f[rs1] as necessary for SEW */
2938        t1 = tcg_temp_new_i64();
2939        if (s->sew == MO_64 && !has_ext(s, RVD)) {
2940            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
2941        } else {
2942            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
2943        }
2944        vec_element_storei(s, a->rd, 0, t1);
2945        tcg_temp_free_i64(t1);
2946        mark_vs_dirty(s);
2947        gen_set_label(over);
2948        return true;
2949    }
2950    return false;
2951}
2952
2953/* Vector Slide Instructions */
2954static bool slideup_check(DisasContext *s, arg_rmrr *a)
2955{
2956    return require_rvv(s) &&
2957           vext_check_isa_ill(s) &&
2958           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
2959}
2960
2961GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
2962GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
2963GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
2964
2965static bool slidedown_check(DisasContext *s, arg_rmrr *a)
2966{
2967    return require_rvv(s) &&
2968           vext_check_isa_ill(s) &&
2969           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
2970}
2971
2972GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
2973GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
2974GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
2975
2976/* Vector Register Gather Instruction */
2977static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
2978{
2979    return require_rvv(s) &&
2980           vext_check_isa_ill(s) &&
2981           require_align(a->rd, s->lmul) &&
2982           require_align(a->rs1, s->lmul) &&
2983           require_align(a->rs2, s->lmul) &&
2984           (a->rd != a->rs2 && a->rd != a->rs1) &&
2985           require_vm(a->vm, a->rd);
2986}
2987
2988GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
2989
2990static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
2991{
2992    return require_rvv(s) &&
2993           vext_check_isa_ill(s) &&
2994           require_align(a->rd, s->lmul) &&
2995           require_align(a->rs2, s->lmul) &&
2996           (a->rd != a->rs2) &&
2997           require_vm(a->vm, a->rd);
2998}
2999
3000/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3001static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3002{
3003    if (!vrgather_vx_check(s, a)) {
3004        return false;
3005    }
3006
3007    if (a->vm && s->vl_eq_vlmax) {
3008        int vlmax = s->vlen;
3009        TCGv_i64 dest = tcg_temp_new_i64();
3010
3011        if (a->rs1 == 0) {
3012            vec_element_loadi(s, dest, a->rs2, 0);
3013        } else {
3014            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3015        }
3016
3017        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3018                             MAXSZ(s), MAXSZ(s), dest);
3019        tcg_temp_free_i64(dest);
3020        mark_vs_dirty(s);
3021    } else {
3022        static gen_helper_opivx * const fns[4] = {
3023            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3024            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3025        };
3026        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3027    }
3028    return true;
3029}
3030
3031/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3032static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3033{
3034    if (!vrgather_vx_check(s, a)) {
3035        return false;
3036    }
3037
3038    if (a->vm && s->vl_eq_vlmax) {
3039        if (a->rs1 >= s->vlen) {
3040            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
3041                                 MAXSZ(s), MAXSZ(s), 0);
3042        } else {
3043            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3044                                 endian_ofs(s, a->rs2, a->rs1),
3045                                 MAXSZ(s), MAXSZ(s));
3046        }
3047        mark_vs_dirty(s);
3048    } else {
3049        static gen_helper_opivx * const fns[4] = {
3050            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3051            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3052        };
3053        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3054                           s, IMM_ZX);
3055    }
3056    return true;
3057}
3058
3059/*
3060 * Vector Compress Instruction
3061 *
3062 * The destination vector register group cannot overlap the
3063 * source vector register group or the source mask register.
3064 */
3065static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3066{
3067    return require_rvv(s) &&
3068           vext_check_isa_ill(s) &&
3069           require_align(a->rd, s->lmul) &&
3070           require_align(a->rs2, s->lmul) &&
3071           (a->rd != a->rs2) &&
3072           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1);
3073}
3074
3075static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3076{
3077    if (vcompress_vm_check(s, a)) {
3078        uint32_t data = 0;
3079        static gen_helper_gvec_4_ptr * const fns[4] = {
3080            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3081            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3082        };
3083        TCGLabel *over = gen_new_label();
3084        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3085
3086        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3087        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3088                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3089                           cpu_env, s->vlen / 8, s->vlen / 8, data,
3090                           fns[s->sew]);
3091        mark_vs_dirty(s);
3092        gen_set_label(over);
3093        return true;
3094    }
3095    return false;
3096}
3097