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