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