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
2102/*
2103 * As RVF-only cpus always have values NaN-boxed to 64-bits,
2104 * RVF and RVD can be treated equally.
2105 * We don't have to deal with the cases of: SEW > FLEN.
2106 *
2107 * If SEW < FLEN, check whether input fp register is a valid
2108 * NaN-boxed value, in which case the least-significant SEW bits
2109 * of the f regsiter are used, else the canonical NaN value is used.
2110 */
2111static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in)
2112{
2113    switch (s->sew) {
2114    case 1:
2115        gen_check_nanbox_h(out, in);
2116        break;
2117    case 2:
2118        gen_check_nanbox_s(out, in);
2119        break;
2120    case 3:
2121        tcg_gen_mov_i64(out, in);
2122        break;
2123    default:
2124        g_assert_not_reached();
2125    }
2126}
2127
2128/* Vector Single-Width Floating-Point Add/Subtract Instructions */
2129
2130/*
2131 * If the current SEW does not correspond to a supported IEEE floating-point
2132 * type, an illegal instruction exception is raised.
2133 */
2134static bool opfvv_check(DisasContext *s, arg_rmrr *a)
2135{
2136    return require_rvv(s) &&
2137           require_rvf(s) &&
2138           vext_check_isa_ill(s) &&
2139           vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
2140}
2141
2142/* OPFVV without GVEC IR */
2143#define GEN_OPFVV_TRANS(NAME, CHECK)                               \
2144static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2145{                                                                  \
2146    if (CHECK(s, a)) {                                             \
2147        uint32_t data = 0;                                         \
2148        static gen_helper_gvec_4_ptr * const fns[3] = {            \
2149            gen_helper_##NAME##_h,                                 \
2150            gen_helper_##NAME##_w,                                 \
2151            gen_helper_##NAME##_d,                                 \
2152        };                                                         \
2153        TCGLabel *over = gen_new_label();                          \
2154        gen_set_rm(s, 7);                                          \
2155        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2156                                                                   \
2157        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2158        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2159        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2160                           vreg_ofs(s, a->rs1),                    \
2161                           vreg_ofs(s, a->rs2), cpu_env,           \
2162                           s->vlen / 8, s->vlen / 8, data,         \
2163                           fns[s->sew - 1]);                       \
2164        mark_vs_dirty(s);                                          \
2165        gen_set_label(over);                                       \
2166        return true;                                               \
2167    }                                                              \
2168    return false;                                                  \
2169}
2170GEN_OPFVV_TRANS(vfadd_vv, opfvv_check)
2171GEN_OPFVV_TRANS(vfsub_vv, opfvv_check)
2172
2173typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr,
2174                              TCGv_env, TCGv_i32);
2175
2176static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
2177                        uint32_t data, gen_helper_opfvf *fn, DisasContext *s)
2178{
2179    TCGv_ptr dest, src2, mask;
2180    TCGv_i32 desc;
2181    TCGv_i64 t1;
2182
2183    TCGLabel *over = gen_new_label();
2184    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2185
2186    dest = tcg_temp_new_ptr();
2187    mask = tcg_temp_new_ptr();
2188    src2 = tcg_temp_new_ptr();
2189    desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2190
2191    tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd));
2192    tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2));
2193    tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2194
2195    /* NaN-box f[rs1] */
2196    t1 = tcg_temp_new_i64();
2197    do_nanbox(s, t1, cpu_fpr[rs1]);
2198
2199    fn(dest, mask, t1, src2, cpu_env, desc);
2200
2201    tcg_temp_free_ptr(dest);
2202    tcg_temp_free_ptr(mask);
2203    tcg_temp_free_ptr(src2);
2204    tcg_temp_free_i64(t1);
2205    mark_vs_dirty(s);
2206    gen_set_label(over);
2207    return true;
2208}
2209
2210/*
2211 * If the current SEW does not correspond to a supported IEEE floating-point
2212 * type, an illegal instruction exception is raised
2213 */
2214static bool opfvf_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_ss(s, a->rd, a->rs2, a->vm);
2220}
2221
2222/* OPFVF without GVEC IR */
2223#define GEN_OPFVF_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_opfvf *const fns[3] = {                 \
2229            gen_helper_##NAME##_h,                                \
2230            gen_helper_##NAME##_w,                                \
2231            gen_helper_##NAME##_d,                                \
2232        };                                                        \
2233        gen_set_rm(s, 7);                                         \
2234        data = FIELD_DP32(data, VDATA, VM, a->vm);                \
2235        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);            \
2236        return opfvf_trans(a->rd, a->rs1, a->rs2, data,           \
2237                           fns[s->sew - 1], s);                   \
2238    }                                                             \
2239    return false;                                                 \
2240}
2241
2242GEN_OPFVF_TRANS(vfadd_vf,  opfvf_check)
2243GEN_OPFVF_TRANS(vfsub_vf,  opfvf_check)
2244GEN_OPFVF_TRANS(vfrsub_vf,  opfvf_check)
2245
2246/* Vector Widening Floating-Point Add/Subtract Instructions */
2247static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
2248{
2249    return require_rvv(s) &&
2250           require_rvf(s) &&
2251           vext_check_isa_ill(s) &&
2252           vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
2253}
2254
2255/* OPFVV with WIDEN */
2256#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK)                       \
2257static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2258{                                                                \
2259    if (CHECK(s, a)) {                                           \
2260        uint32_t data = 0;                                       \
2261        static gen_helper_gvec_4_ptr * const fns[2] = {          \
2262            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2263        };                                                       \
2264        TCGLabel *over = gen_new_label();                        \
2265        gen_set_rm(s, 7);                                        \
2266        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);        \
2267                                                                 \
2268        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2269        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2270        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),   \
2271                           vreg_ofs(s, a->rs1),                  \
2272                           vreg_ofs(s, a->rs2), cpu_env,         \
2273                           s->vlen / 8, s->vlen / 8, data,       \
2274                           fns[s->sew - 1]);                     \
2275        mark_vs_dirty(s);                                        \
2276        gen_set_label(over);                                     \
2277        return true;                                             \
2278    }                                                            \
2279    return false;                                                \
2280}
2281
2282GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check)
2283GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check)
2284
2285static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
2286{
2287    return require_rvv(s) &&
2288           require_rvf(s) &&
2289           vext_check_isa_ill(s) &&
2290           vext_check_ds(s, a->rd, a->rs2, a->vm);
2291}
2292
2293/* OPFVF with WIDEN */
2294#define GEN_OPFVF_WIDEN_TRANS(NAME)                              \
2295static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2296{                                                                \
2297    if (opfvf_widen_check(s, a)) {                               \
2298        uint32_t data = 0;                                       \
2299        static gen_helper_opfvf *const fns[2] = {                \
2300            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2301        };                                                       \
2302        gen_set_rm(s, 7);                                        \
2303        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2304        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2305        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2306                           fns[s->sew - 1], s);                  \
2307    }                                                            \
2308    return false;                                                \
2309}
2310
2311GEN_OPFVF_WIDEN_TRANS(vfwadd_vf)
2312GEN_OPFVF_WIDEN_TRANS(vfwsub_vf)
2313
2314static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
2315{
2316    return require_rvv(s) &&
2317           require_rvf(s) &&
2318           vext_check_isa_ill(s) &&
2319           vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
2320}
2321
2322/* WIDEN OPFVV with WIDEN */
2323#define GEN_OPFWV_WIDEN_TRANS(NAME)                                \
2324static bool trans_##NAME(DisasContext *s, arg_rmrr *a)             \
2325{                                                                  \
2326    if (opfwv_widen_check(s, a)) {                                 \
2327        uint32_t data = 0;                                         \
2328        static gen_helper_gvec_4_ptr * const fns[2] = {            \
2329            gen_helper_##NAME##_h, gen_helper_##NAME##_w,          \
2330        };                                                         \
2331        TCGLabel *over = gen_new_label();                          \
2332        gen_set_rm(s, 7);                                          \
2333        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2334                                                                   \
2335        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2336        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2337        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2338                           vreg_ofs(s, a->rs1),                    \
2339                           vreg_ofs(s, a->rs2), cpu_env,           \
2340                           s->vlen / 8, s->vlen / 8, data,         \
2341                           fns[s->sew - 1]);                       \
2342        mark_vs_dirty(s);                                          \
2343        gen_set_label(over);                                       \
2344        return true;                                               \
2345    }                                                              \
2346    return false;                                                  \
2347}
2348
2349GEN_OPFWV_WIDEN_TRANS(vfwadd_wv)
2350GEN_OPFWV_WIDEN_TRANS(vfwsub_wv)
2351
2352static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
2353{
2354    return require_rvv(s) &&
2355           require_rvf(s) &&
2356           vext_check_isa_ill(s) &&
2357           vext_check_dd(s, a->rd, a->rs2, a->vm);
2358}
2359
2360/* WIDEN OPFVF with WIDEN */
2361#define GEN_OPFWF_WIDEN_TRANS(NAME)                              \
2362static bool trans_##NAME(DisasContext *s, arg_rmrr *a)           \
2363{                                                                \
2364    if (opfwf_widen_check(s, a)) {                               \
2365        uint32_t data = 0;                                       \
2366        static gen_helper_opfvf *const fns[2] = {                \
2367            gen_helper_##NAME##_h, gen_helper_##NAME##_w,        \
2368        };                                                       \
2369        gen_set_rm(s, 7);                                        \
2370        data = FIELD_DP32(data, VDATA, VM, a->vm);               \
2371        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);           \
2372        return opfvf_trans(a->rd, a->rs1, a->rs2, data,          \
2373                           fns[s->sew - 1], s);                  \
2374    }                                                            \
2375    return false;                                                \
2376}
2377
2378GEN_OPFWF_WIDEN_TRANS(vfwadd_wf)
2379GEN_OPFWF_WIDEN_TRANS(vfwsub_wf)
2380
2381/* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2382GEN_OPFVV_TRANS(vfmul_vv, opfvv_check)
2383GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check)
2384GEN_OPFVF_TRANS(vfmul_vf,  opfvf_check)
2385GEN_OPFVF_TRANS(vfdiv_vf,  opfvf_check)
2386GEN_OPFVF_TRANS(vfrdiv_vf,  opfvf_check)
2387
2388/* Vector Widening Floating-Point Multiply */
2389GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check)
2390GEN_OPFVF_WIDEN_TRANS(vfwmul_vf)
2391
2392/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2393GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check)
2394GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check)
2395GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check)
2396GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check)
2397GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check)
2398GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check)
2399GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check)
2400GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check)
2401GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check)
2402GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check)
2403GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check)
2404GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check)
2405GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check)
2406GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check)
2407GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check)
2408GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check)
2409
2410/* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2411GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check)
2412GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check)
2413GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check)
2414GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check)
2415GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf)
2416GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf)
2417GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf)
2418GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf)
2419
2420/* Vector Floating-Point Square-Root Instruction */
2421
2422/*
2423 * If the current SEW does not correspond to a supported IEEE floating-point
2424 * type, an illegal instruction exception is raised
2425 */
2426static bool opfv_check(DisasContext *s, arg_rmr *a)
2427{
2428    return require_rvv(s) &&
2429           require_rvf(s) &&
2430           vext_check_isa_ill(s) &&
2431           /* OPFV instructions ignore vs1 check */
2432           vext_check_ss(s, a->rd, a->rs2, a->vm);
2433}
2434
2435#define GEN_OPFV_TRANS(NAME, CHECK)                                \
2436static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2437{                                                                  \
2438    if (CHECK(s, a)) {                                             \
2439        uint32_t data = 0;                                         \
2440        static gen_helper_gvec_3_ptr * const fns[3] = {            \
2441            gen_helper_##NAME##_h,                                 \
2442            gen_helper_##NAME##_w,                                 \
2443            gen_helper_##NAME##_d,                                 \
2444        };                                                         \
2445        TCGLabel *over = gen_new_label();                          \
2446        gen_set_rm(s, 7);                                          \
2447        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2448                                                                   \
2449        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2450        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2451        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2452                           vreg_ofs(s, a->rs2), cpu_env,           \
2453                           s->vlen / 8, s->vlen / 8, data,         \
2454                           fns[s->sew - 1]);                       \
2455        mark_vs_dirty(s);                                          \
2456        gen_set_label(over);                                       \
2457        return true;                                               \
2458    }                                                              \
2459    return false;                                                  \
2460}
2461
2462GEN_OPFV_TRANS(vfsqrt_v, opfv_check)
2463
2464/* Vector Floating-Point MIN/MAX Instructions */
2465GEN_OPFVV_TRANS(vfmin_vv, opfvv_check)
2466GEN_OPFVV_TRANS(vfmax_vv, opfvv_check)
2467GEN_OPFVF_TRANS(vfmin_vf, opfvf_check)
2468GEN_OPFVF_TRANS(vfmax_vf, opfvf_check)
2469
2470/* Vector Floating-Point Sign-Injection Instructions */
2471GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check)
2472GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check)
2473GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check)
2474GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check)
2475GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check)
2476GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check)
2477
2478/* Vector Floating-Point Compare Instructions */
2479static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
2480{
2481    return require_rvv(s) &&
2482           require_rvf(s) &&
2483           vext_check_isa_ill(s) &&
2484           vext_check_mss(s, a->rd, a->rs1, a->rs2);
2485}
2486
2487GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
2488GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check)
2489GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check)
2490GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check)
2491GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check)
2492
2493static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
2494{
2495    return require_rvv(s) &&
2496           require_rvf(s) &&
2497           vext_check_isa_ill(s) &&
2498           vext_check_ms(s, a->rd, a->rs2);
2499}
2500
2501GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
2502GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check)
2503GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check)
2504GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check)
2505GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check)
2506GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check)
2507GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check)
2508
2509/* Vector Floating-Point Classify Instruction */
2510GEN_OPFV_TRANS(vfclass_v, opfv_check)
2511
2512/* Vector Floating-Point Merge Instruction */
2513GEN_OPFVF_TRANS(vfmerge_vfm,  opfvf_check)
2514
2515static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
2516{
2517    if (require_rvv(s) &&
2518        require_rvf(s) &&
2519        vext_check_isa_ill(s) &&
2520        require_align(a->rd, s->lmul)) {
2521        if (s->vl_eq_vlmax) {
2522            tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
2523                                 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]);
2524            mark_vs_dirty(s);
2525        } else {
2526            TCGv_ptr dest;
2527            TCGv_i32 desc;
2528            uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul);
2529            static gen_helper_vmv_vx * const fns[3] = {
2530                gen_helper_vmv_v_x_h,
2531                gen_helper_vmv_v_x_w,
2532                gen_helper_vmv_v_x_d,
2533            };
2534            TCGLabel *over = gen_new_label();
2535            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2536
2537            dest = tcg_temp_new_ptr();
2538            desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2539            tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd));
2540            fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc);
2541
2542            tcg_temp_free_ptr(dest);
2543            mark_vs_dirty(s);
2544            gen_set_label(over);
2545        }
2546        return true;
2547    }
2548    return false;
2549}
2550
2551/* Single-Width Floating-Point/Integer Type-Convert Instructions */
2552GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check)
2553GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check)
2554GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check)
2555GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check)
2556
2557/* Widening Floating-Point/Integer Type-Convert Instructions */
2558
2559/*
2560 * If the current SEW does not correspond to a supported IEEE floating-point
2561 * type, an illegal instruction exception is raised
2562 */
2563static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
2564{
2565    return require_rvv(s) &&
2566           require_scale_rvf(s) &&
2567           (s->sew != MO_8) &&
2568           vext_check_isa_ill(s) &&
2569           vext_check_ds(s, a->rd, a->rs2, a->vm);
2570}
2571
2572#define GEN_OPFV_WIDEN_TRANS(NAME)                                 \
2573static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2574{                                                                  \
2575    if (opfv_widen_check(s, a)) {                                  \
2576        uint32_t data = 0;                                         \
2577        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2578            gen_helper_##NAME##_h,                                 \
2579            gen_helper_##NAME##_w,                                 \
2580        };                                                         \
2581        TCGLabel *over = gen_new_label();                          \
2582        gen_set_rm(s, 7);                                          \
2583        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2584                                                                   \
2585        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2586        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2587        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2588                           vreg_ofs(s, a->rs2), cpu_env,           \
2589                           s->vlen / 8, s->vlen / 8, data,         \
2590                           fns[s->sew - 1]);                       \
2591        mark_vs_dirty(s);                                          \
2592        gen_set_label(over);                                       \
2593        return true;                                               \
2594    }                                                              \
2595    return false;                                                  \
2596}
2597
2598GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v)
2599GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v)
2600GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v)
2601GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v)
2602GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v)
2603
2604/* Narrowing Floating-Point/Integer Type-Convert Instructions */
2605
2606/*
2607 * If the current SEW does not correspond to a supported IEEE floating-point
2608 * type, an illegal instruction exception is raised
2609 */
2610static bool opfv_narrow_check(DisasContext *s, arg_rmr *a)
2611{
2612    return require_rvv(s) &&
2613           require_rvf(s) &&
2614           (s->sew != MO_64) &&
2615           vext_check_isa_ill(s) &&
2616           /* OPFV narrowing instructions ignore vs1 check */
2617           vext_check_sd(s, a->rd, a->rs2, a->vm);
2618}
2619
2620#define GEN_OPFV_NARROW_TRANS(NAME)                                \
2621static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2622{                                                                  \
2623    if (opfv_narrow_check(s, a)) {                                 \
2624        uint32_t data = 0;                                         \
2625        static gen_helper_gvec_3_ptr * const fns[2] = {            \
2626            gen_helper_##NAME##_h,                                 \
2627            gen_helper_##NAME##_w,                                 \
2628        };                                                         \
2629        TCGLabel *over = gen_new_label();                          \
2630        gen_set_rm(s, 7);                                          \
2631        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2632                                                                   \
2633        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2634        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2635        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2636                           vreg_ofs(s, a->rs2), cpu_env,           \
2637                           s->vlen / 8, s->vlen / 8, data,         \
2638                           fns[s->sew - 1]);                       \
2639        mark_vs_dirty(s);                                          \
2640        gen_set_label(over);                                       \
2641        return true;                                               \
2642    }                                                              \
2643    return false;                                                  \
2644}
2645
2646GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v)
2647GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v)
2648GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v)
2649GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v)
2650GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v)
2651
2652/*
2653 *** Vector Reduction Operations
2654 */
2655/* Vector Single-Width Integer Reduction Instructions */
2656static bool reduction_check(DisasContext *s, arg_rmrr *a)
2657{
2658    return require_rvv(s) &&
2659           vext_check_isa_ill(s) &&
2660           vext_check_reduction(s, a->rs2);
2661}
2662
2663GEN_OPIVV_TRANS(vredsum_vs, reduction_check)
2664GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check)
2665GEN_OPIVV_TRANS(vredmax_vs, reduction_check)
2666GEN_OPIVV_TRANS(vredminu_vs, reduction_check)
2667GEN_OPIVV_TRANS(vredmin_vs, reduction_check)
2668GEN_OPIVV_TRANS(vredand_vs, reduction_check)
2669GEN_OPIVV_TRANS(vredor_vs, reduction_check)
2670GEN_OPIVV_TRANS(vredxor_vs, reduction_check)
2671
2672/* Vector Widening Integer Reduction Instructions */
2673static bool reduction_widen_check(DisasContext *s, arg_rmrr *a)
2674{
2675    return reduction_check(s, a) && (s->sew < MO_64);
2676}
2677
2678GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check)
2679GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
2680
2681/* Vector Single-Width Floating-Point Reduction Instructions */
2682GEN_OPFVV_TRANS(vfredsum_vs, reduction_check)
2683GEN_OPFVV_TRANS(vfredmax_vs, reduction_check)
2684GEN_OPFVV_TRANS(vfredmin_vs, reduction_check)
2685
2686/* Vector Widening Floating-Point Reduction Instructions */
2687GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check)
2688
2689/*
2690 *** Vector Mask Operations
2691 */
2692
2693/* Vector Mask-Register Logical Instructions */
2694#define GEN_MM_TRANS(NAME)                                         \
2695static bool trans_##NAME(DisasContext *s, arg_r *a)                \
2696{                                                                  \
2697    if (vext_check_isa_ill(s)) {                                   \
2698        uint32_t data = 0;                                         \
2699        gen_helper_gvec_4_ptr *fn = gen_helper_##NAME;             \
2700        TCGLabel *over = gen_new_label();                          \
2701        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2702                                                                   \
2703        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2704        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),     \
2705                           vreg_ofs(s, a->rs1),                    \
2706                           vreg_ofs(s, a->rs2), cpu_env,           \
2707                           s->vlen / 8, s->vlen / 8, data, fn);    \
2708        mark_vs_dirty(s);                                          \
2709        gen_set_label(over);                                       \
2710        return true;                                               \
2711    }                                                              \
2712    return false;                                                  \
2713}
2714
2715GEN_MM_TRANS(vmand_mm)
2716GEN_MM_TRANS(vmnand_mm)
2717GEN_MM_TRANS(vmandnot_mm)
2718GEN_MM_TRANS(vmxor_mm)
2719GEN_MM_TRANS(vmor_mm)
2720GEN_MM_TRANS(vmnor_mm)
2721GEN_MM_TRANS(vmornot_mm)
2722GEN_MM_TRANS(vmxnor_mm)
2723
2724/* Vector mask population count vmpopc */
2725static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a)
2726{
2727    if (require_rvv(s) &&
2728        vext_check_isa_ill(s)) {
2729        TCGv_ptr src2, mask;
2730        TCGv dst;
2731        TCGv_i32 desc;
2732        uint32_t data = 0;
2733        data = FIELD_DP32(data, VDATA, VM, a->vm);
2734        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2735
2736        mask = tcg_temp_new_ptr();
2737        src2 = tcg_temp_new_ptr();
2738        dst = dest_gpr(s, a->rd);
2739        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2740
2741        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2742        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2743
2744        gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc);
2745        gen_set_gpr(s, a->rd, dst);
2746
2747        tcg_temp_free_ptr(mask);
2748        tcg_temp_free_ptr(src2);
2749        return true;
2750    }
2751    return false;
2752}
2753
2754/* vmfirst find-first-set mask bit */
2755static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a)
2756{
2757    if (require_rvv(s) &&
2758        vext_check_isa_ill(s)) {
2759        TCGv_ptr src2, mask;
2760        TCGv dst;
2761        TCGv_i32 desc;
2762        uint32_t data = 0;
2763        data = FIELD_DP32(data, VDATA, VM, a->vm);
2764        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2765
2766        mask = tcg_temp_new_ptr();
2767        src2 = tcg_temp_new_ptr();
2768        dst = dest_gpr(s, a->rd);
2769        desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data));
2770
2771        tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2));
2772        tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0));
2773
2774        gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc);
2775        gen_set_gpr(s, a->rd, dst);
2776
2777        tcg_temp_free_ptr(mask);
2778        tcg_temp_free_ptr(src2);
2779        return true;
2780    }
2781    return false;
2782}
2783
2784/* vmsbf.m set-before-first mask bit */
2785/* vmsif.m set-includ-first mask bit */
2786/* vmsof.m set-only-first mask bit */
2787#define GEN_M_TRANS(NAME)                                          \
2788static bool trans_##NAME(DisasContext *s, arg_rmr *a)              \
2789{                                                                  \
2790    if (vext_check_isa_ill(s)) {                                   \
2791        uint32_t data = 0;                                         \
2792        gen_helper_gvec_3_ptr *fn = gen_helper_##NAME;             \
2793        TCGLabel *over = gen_new_label();                          \
2794        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);          \
2795                                                                   \
2796        data = FIELD_DP32(data, VDATA, VM, a->vm);                 \
2797        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);             \
2798        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd),                     \
2799                           vreg_ofs(s, 0), vreg_ofs(s, a->rs2),    \
2800                           cpu_env, s->vlen / 8, s->vlen / 8,      \
2801                           data, fn);                              \
2802        mark_vs_dirty(s);                                          \
2803        gen_set_label(over);                                       \
2804        return true;                                               \
2805    }                                                              \
2806    return false;                                                  \
2807}
2808
2809GEN_M_TRANS(vmsbf_m)
2810GEN_M_TRANS(vmsif_m)
2811GEN_M_TRANS(vmsof_m)
2812
2813/* Vector Iota Instruction */
2814static bool trans_viota_m(DisasContext *s, arg_viota_m *a)
2815{
2816    if (require_rvv(s) &&
2817        vext_check_isa_ill(s) &&
2818        require_noover(a->rd, s->lmul, a->rs2, 0) &&
2819        require_vm(a->vm, a->rd) &&
2820        require_align(a->rd, s->lmul)) {
2821        uint32_t data = 0;
2822        TCGLabel *over = gen_new_label();
2823        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2824
2825        data = FIELD_DP32(data, VDATA, VM, a->vm);
2826        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2827        static gen_helper_gvec_3_ptr * const fns[4] = {
2828            gen_helper_viota_m_b, gen_helper_viota_m_h,
2829            gen_helper_viota_m_w, gen_helper_viota_m_d,
2830        };
2831        tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2832                           vreg_ofs(s, a->rs2), cpu_env,
2833                           s->vlen / 8, s->vlen / 8, data, fns[s->sew]);
2834        mark_vs_dirty(s);
2835        gen_set_label(over);
2836        return true;
2837    }
2838    return false;
2839}
2840
2841/* Vector Element Index Instruction */
2842static bool trans_vid_v(DisasContext *s, arg_vid_v *a)
2843{
2844    if (require_rvv(s) &&
2845        vext_check_isa_ill(s) &&
2846        require_align(a->rd, s->lmul) &&
2847        require_vm(a->vm, a->rd)) {
2848        uint32_t data = 0;
2849        TCGLabel *over = gen_new_label();
2850        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
2851
2852        data = FIELD_DP32(data, VDATA, VM, a->vm);
2853        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
2854        static gen_helper_gvec_2_ptr * const fns[4] = {
2855            gen_helper_vid_v_b, gen_helper_vid_v_h,
2856            gen_helper_vid_v_w, gen_helper_vid_v_d,
2857        };
2858        tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
2859                           cpu_env, s->vlen / 8, s->vlen / 8,
2860                           data, fns[s->sew]);
2861        mark_vs_dirty(s);
2862        gen_set_label(over);
2863        return true;
2864    }
2865    return false;
2866}
2867
2868/*
2869 *** Vector Permutation Instructions
2870 */
2871
2872/* Integer Extract Instruction */
2873
2874static void load_element(TCGv_i64 dest, TCGv_ptr base,
2875                         int ofs, int sew)
2876{
2877    switch (sew) {
2878    case MO_8:
2879        tcg_gen_ld8u_i64(dest, base, ofs);
2880        break;
2881    case MO_16:
2882        tcg_gen_ld16u_i64(dest, base, ofs);
2883        break;
2884    case MO_32:
2885        tcg_gen_ld32u_i64(dest, base, ofs);
2886        break;
2887    case MO_64:
2888        tcg_gen_ld_i64(dest, base, ofs);
2889        break;
2890    default:
2891        g_assert_not_reached();
2892        break;
2893    }
2894}
2895
2896/* offset of the idx element with base regsiter r */
2897static uint32_t endian_ofs(DisasContext *s, int r, int idx)
2898{
2899#ifdef HOST_WORDS_BIGENDIAN
2900    return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew);
2901#else
2902    return vreg_ofs(s, r) + (idx << s->sew);
2903#endif
2904}
2905
2906/* adjust the index according to the endian */
2907static void endian_adjust(TCGv_i32 ofs, int sew)
2908{
2909#ifdef HOST_WORDS_BIGENDIAN
2910    tcg_gen_xori_i32(ofs, ofs, 7 >> sew);
2911#endif
2912}
2913
2914/* Load idx >= VLMAX ? 0 : vreg[idx] */
2915static void vec_element_loadx(DisasContext *s, TCGv_i64 dest,
2916                              int vreg, TCGv idx, int vlmax)
2917{
2918    TCGv_i32 ofs = tcg_temp_new_i32();
2919    TCGv_ptr base = tcg_temp_new_ptr();
2920    TCGv_i64 t_idx = tcg_temp_new_i64();
2921    TCGv_i64 t_vlmax, t_zero;
2922
2923    /*
2924     * Mask the index to the length so that we do
2925     * not produce an out-of-range load.
2926     */
2927    tcg_gen_trunc_tl_i32(ofs, idx);
2928    tcg_gen_andi_i32(ofs, ofs, vlmax - 1);
2929
2930    /* Convert the index to an offset. */
2931    endian_adjust(ofs, s->sew);
2932    tcg_gen_shli_i32(ofs, ofs, s->sew);
2933
2934    /* Convert the index to a pointer. */
2935    tcg_gen_ext_i32_ptr(base, ofs);
2936    tcg_gen_add_ptr(base, base, cpu_env);
2937
2938    /* Perform the load. */
2939    load_element(dest, base,
2940                 vreg_ofs(s, vreg), s->sew);
2941    tcg_temp_free_ptr(base);
2942    tcg_temp_free_i32(ofs);
2943
2944    /* Flush out-of-range indexing to zero.  */
2945    t_vlmax = tcg_constant_i64(vlmax);
2946    t_zero = tcg_constant_i64(0);
2947    tcg_gen_extu_tl_i64(t_idx, idx);
2948
2949    tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx,
2950                        t_vlmax, dest, t_zero);
2951
2952    tcg_temp_free_i64(t_idx);
2953}
2954
2955static void vec_element_loadi(DisasContext *s, TCGv_i64 dest,
2956                              int vreg, int idx)
2957{
2958    load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew);
2959}
2960
2961static bool trans_vext_x_v(DisasContext *s, arg_r *a)
2962{
2963    TCGv_i64 tmp = tcg_temp_new_i64();
2964    TCGv dest = dest_gpr(s, a->rd);
2965
2966    if (a->rs1 == 0) {
2967        /* Special case vmv.x.s rd, vs2. */
2968        vec_element_loadi(s, tmp, a->rs2, 0);
2969    } else {
2970        /* This instruction ignores LMUL and vector register groups */
2971        int vlmax = s->vlen >> (3 + s->sew);
2972        vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax);
2973    }
2974
2975    tcg_gen_trunc_i64_tl(dest, tmp);
2976    gen_set_gpr(s, a->rd, dest);
2977
2978    tcg_temp_free_i64(tmp);
2979    return true;
2980}
2981
2982/* Integer Scalar Move Instruction */
2983
2984static void store_element(TCGv_i64 val, TCGv_ptr base,
2985                          int ofs, int sew)
2986{
2987    switch (sew) {
2988    case MO_8:
2989        tcg_gen_st8_i64(val, base, ofs);
2990        break;
2991    case MO_16:
2992        tcg_gen_st16_i64(val, base, ofs);
2993        break;
2994    case MO_32:
2995        tcg_gen_st32_i64(val, base, ofs);
2996        break;
2997    case MO_64:
2998        tcg_gen_st_i64(val, base, ofs);
2999        break;
3000    default:
3001        g_assert_not_reached();
3002        break;
3003    }
3004}
3005
3006/*
3007 * Store vreg[idx] = val.
3008 * The index must be in range of VLMAX.
3009 */
3010static void vec_element_storei(DisasContext *s, int vreg,
3011                               int idx, TCGv_i64 val)
3012{
3013    store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew);
3014}
3015
3016/* vmv.s.x vd, rs1 # vd[0] = rs1 */
3017static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a)
3018{
3019    if (vext_check_isa_ill(s)) {
3020        /* This instruction ignores LMUL and vector register groups */
3021        int maxsz = s->vlen >> 3;
3022        TCGv_i64 t1;
3023        TCGLabel *over = gen_new_label();
3024
3025        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3026        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0);
3027        if (a->rs1 == 0) {
3028            goto done;
3029        }
3030
3031        t1 = tcg_temp_new_i64();
3032        tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]);
3033        vec_element_storei(s, a->rd, 0, t1);
3034        tcg_temp_free_i64(t1);
3035        mark_vs_dirty(s);
3036    done:
3037        gen_set_label(over);
3038        return true;
3039    }
3040    return false;
3041}
3042
3043/* Floating-Point Scalar Move Instructions */
3044static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
3045{
3046    if (!s->vill && has_ext(s, RVF) &&
3047        (s->mstatus_fs != 0) && (s->sew != 0)) {
3048        unsigned int len = 8 << s->sew;
3049
3050        vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0);
3051        if (len < 64) {
3052            tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd],
3053                            MAKE_64BIT_MASK(len, 64 - len));
3054        }
3055
3056        mark_fs_dirty(s);
3057        return true;
3058    }
3059    return false;
3060}
3061
3062/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
3063static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
3064{
3065    if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) {
3066        TCGv_i64 t1;
3067        /* The instructions ignore LMUL and vector register group. */
3068        uint32_t vlmax = s->vlen >> 3;
3069
3070        /* if vl == 0, skip vector register write back */
3071        TCGLabel *over = gen_new_label();
3072        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3073
3074        /* zeroed all elements */
3075        tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0);
3076
3077        /* NaN-box f[rs1] as necessary for SEW */
3078        t1 = tcg_temp_new_i64();
3079        if (s->sew == MO_64 && !has_ext(s, RVD)) {
3080            tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32));
3081        } else {
3082            tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]);
3083        }
3084        vec_element_storei(s, a->rd, 0, t1);
3085        tcg_temp_free_i64(t1);
3086        mark_vs_dirty(s);
3087        gen_set_label(over);
3088        return true;
3089    }
3090    return false;
3091}
3092
3093/* Vector Slide Instructions */
3094static bool slideup_check(DisasContext *s, arg_rmrr *a)
3095{
3096    return require_rvv(s) &&
3097           vext_check_isa_ill(s) &&
3098           vext_check_slide(s, a->rd, a->rs2, a->vm, true);
3099}
3100
3101GEN_OPIVX_TRANS(vslideup_vx, slideup_check)
3102GEN_OPIVX_TRANS(vslide1up_vx, slideup_check)
3103GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check)
3104
3105static bool slidedown_check(DisasContext *s, arg_rmrr *a)
3106{
3107    return require_rvv(s) &&
3108           vext_check_isa_ill(s) &&
3109           vext_check_slide(s, a->rd, a->rs2, a->vm, false);
3110}
3111
3112GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check)
3113GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check)
3114GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
3115
3116/* Vector Register Gather Instruction */
3117static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a)
3118{
3119    return require_rvv(s) &&
3120           vext_check_isa_ill(s) &&
3121           require_align(a->rd, s->lmul) &&
3122           require_align(a->rs1, s->lmul) &&
3123           require_align(a->rs2, s->lmul) &&
3124           (a->rd != a->rs2 && a->rd != a->rs1) &&
3125           require_vm(a->vm, a->rd);
3126}
3127
3128GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check)
3129
3130static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a)
3131{
3132    return require_rvv(s) &&
3133           vext_check_isa_ill(s) &&
3134           require_align(a->rd, s->lmul) &&
3135           require_align(a->rs2, s->lmul) &&
3136           (a->rd != a->rs2) &&
3137           require_vm(a->vm, a->rd);
3138}
3139
3140/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
3141static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a)
3142{
3143    if (!vrgather_vx_check(s, a)) {
3144        return false;
3145    }
3146
3147    if (a->vm && s->vl_eq_vlmax) {
3148        int vlmax = s->vlen;
3149        TCGv_i64 dest = tcg_temp_new_i64();
3150
3151        if (a->rs1 == 0) {
3152            vec_element_loadi(s, dest, a->rs2, 0);
3153        } else {
3154            vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax);
3155        }
3156
3157        tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd),
3158                             MAXSZ(s), MAXSZ(s), dest);
3159        tcg_temp_free_i64(dest);
3160        mark_vs_dirty(s);
3161    } else {
3162        static gen_helper_opivx * const fns[4] = {
3163            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3164            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3165        };
3166        return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);
3167    }
3168    return true;
3169}
3170
3171/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
3172static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a)
3173{
3174    if (!vrgather_vx_check(s, a)) {
3175        return false;
3176    }
3177
3178    if (a->vm && s->vl_eq_vlmax) {
3179        if (a->rs1 >= s->vlen) {
3180            tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd),
3181                                 MAXSZ(s), MAXSZ(s), 0);
3182        } else {
3183            tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd),
3184                                 endian_ofs(s, a->rs2, a->rs1),
3185                                 MAXSZ(s), MAXSZ(s));
3186        }
3187        mark_vs_dirty(s);
3188    } else {
3189        static gen_helper_opivx * const fns[4] = {
3190            gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h,
3191            gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d
3192        };
3193        return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew],
3194                           s, IMM_ZX);
3195    }
3196    return true;
3197}
3198
3199/*
3200 * Vector Compress Instruction
3201 *
3202 * The destination vector register group cannot overlap the
3203 * source vector register group or the source mask register.
3204 */
3205static bool vcompress_vm_check(DisasContext *s, arg_r *a)
3206{
3207    return require_rvv(s) &&
3208           vext_check_isa_ill(s) &&
3209           require_align(a->rd, s->lmul) &&
3210           require_align(a->rs2, s->lmul) &&
3211           (a->rd != a->rs2) &&
3212           !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1);
3213}
3214
3215static bool trans_vcompress_vm(DisasContext *s, arg_r *a)
3216{
3217    if (vcompress_vm_check(s, a)) {
3218        uint32_t data = 0;
3219        static gen_helper_gvec_4_ptr * const fns[4] = {
3220            gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h,
3221            gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d,
3222        };
3223        TCGLabel *over = gen_new_label();
3224        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over);
3225
3226        data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
3227        tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0),
3228                           vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2),
3229                           cpu_env, s->vlen / 8, s->vlen / 8, data,
3230                           fns[s->sew]);
3231        mark_vs_dirty(s);
3232        gen_set_label(over);
3233        return true;
3234    }
3235    return false;
3236}
3237