2 * RISC-V translation routines for the RVV Standard Extension.
4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved.
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.
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
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/>.
18 #include "tcg/tcg-op-gvec.h"
19 #include "tcg/tcg-gvec-desc.h"
20 #include "internals.h"
22 static bool trans_vsetvl(DisasContext
*ctx
, arg_vsetvl
*a
)
26 if (!has_ext(ctx
, RVV
)) {
33 /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
35 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
36 s1
= tcg_const_tl(RV_VLEN_MAX
);
39 gen_get_gpr(s1
, a
->rs1
);
41 gen_get_gpr(s2
, a
->rs2
);
42 gen_helper_vsetvl(dst
, cpu_env
, s1
, s2
);
43 gen_set_gpr(a
->rd
, dst
);
44 tcg_gen_movi_tl(cpu_pc
, ctx
->pc_succ_insn
);
45 lookup_and_goto_ptr(ctx
);
46 ctx
->base
.is_jmp
= DISAS_NORETURN
;
54 static bool trans_vsetvli(DisasContext
*ctx
, arg_vsetvli
*a
)
58 if (!has_ext(ctx
, RVV
)) {
62 s2
= tcg_const_tl(a
->zimm
);
65 /* Using x0 as the rs1 register specifier, encodes an infinite AVL */
67 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */
68 s1
= tcg_const_tl(RV_VLEN_MAX
);
71 gen_get_gpr(s1
, a
->rs1
);
73 gen_helper_vsetvl(dst
, cpu_env
, s1
, s2
);
74 gen_set_gpr(a
->rd
, dst
);
75 gen_goto_tb(ctx
, 0, ctx
->pc_succ_insn
);
76 ctx
->base
.is_jmp
= DISAS_NORETURN
;
84 /* vector register offset from env */
85 static uint32_t vreg_ofs(DisasContext
*s
, int reg
)
87 return offsetof(CPURISCVState
, vreg
) + reg
* s
->vlen
/ 8;
93 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present.
94 * So RVV is also be checked in this function.
96 static bool vext_check_isa_ill(DisasContext
*s
)
102 * There are two rules check here.
104 * 1. Vector register numbers are multiples of LMUL. (Section 3.2)
106 * 2. For all widening instructions, the destination LMUL value must also be
107 * a supported LMUL value. (Section 11.2)
109 static bool vext_check_reg(DisasContext
*s
, uint32_t reg
, bool widen
)
112 * The destination vector register group results are arranged as if both
113 * SEW and LMUL were at twice their current settings. (Section 11.2).
115 int legal
= widen
? 2 << s
->lmul
: 1 << s
->lmul
;
117 return !((s
->lmul
== 0x3 && widen
) || (reg
% legal
));
121 * There are two rules check here.
123 * 1. The destination vector register group for a masked vector instruction can
124 * only overlap the source mask register (v0) when LMUL=1. (Section 5.3)
126 * 2. In widen instructions and some other insturctions, like vslideup.vx,
127 * there is no need to check whether LMUL=1.
129 static bool vext_check_overlap_mask(DisasContext
*s
, uint32_t vd
, bool vm
,
132 return (vm
!= 0 || vd
!= 0) || (!force
&& (s
->lmul
== 0));
135 /* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */
136 static bool vext_check_nf(DisasContext
*s
, uint32_t nf
)
138 return (1 << s
->lmul
) * nf
<= 8;
142 * The destination vector register group cannot overlap a source vector register
143 * group of a different element width. (Section 11.2)
145 static inline bool vext_check_overlap_group(int rd
, int dlen
, int rs
, int slen
)
147 return ((rd
>= rs
+ slen
) || (rs
>= rd
+ dlen
));
149 /* common translation macro */
150 #define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \
151 static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\
154 return OP(s, a, SEQ); \
160 *** unit stride load and store
162 typedef void gen_helper_ldst_us(TCGv_ptr
, TCGv_ptr
, TCGv
,
165 static bool ldst_us_trans(uint32_t vd
, uint32_t rs1
, uint32_t data
,
166 gen_helper_ldst_us
*fn
, DisasContext
*s
)
172 TCGLabel
*over
= gen_new_label();
173 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
175 dest
= tcg_temp_new_ptr();
176 mask
= tcg_temp_new_ptr();
177 base
= tcg_temp_new();
180 * As simd_desc supports at most 256 bytes, and in this implementation,
181 * the max vector group length is 2048 bytes. So split it into two parts.
183 * The first part is vlen in bytes, encoded in maxsz of simd_desc.
184 * The second part is lmul, encoded in data of simd_desc.
186 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
188 gen_get_gpr(base
, rs1
);
189 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
190 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
192 fn(dest
, mask
, base
, cpu_env
, desc
);
194 tcg_temp_free_ptr(dest
);
195 tcg_temp_free_ptr(mask
);
197 tcg_temp_free_i32(desc
);
202 static bool ld_us_op(DisasContext
*s
, arg_r2nfvm
*a
, uint8_t seq
)
205 gen_helper_ldst_us
*fn
;
206 static gen_helper_ldst_us
* const fns
[2][7][4] = {
207 /* masked unit stride load */
208 { { gen_helper_vlb_v_b_mask
, gen_helper_vlb_v_h_mask
,
209 gen_helper_vlb_v_w_mask
, gen_helper_vlb_v_d_mask
},
210 { NULL
, gen_helper_vlh_v_h_mask
,
211 gen_helper_vlh_v_w_mask
, gen_helper_vlh_v_d_mask
},
213 gen_helper_vlw_v_w_mask
, gen_helper_vlw_v_d_mask
},
214 { gen_helper_vle_v_b_mask
, gen_helper_vle_v_h_mask
,
215 gen_helper_vle_v_w_mask
, gen_helper_vle_v_d_mask
},
216 { gen_helper_vlbu_v_b_mask
, gen_helper_vlbu_v_h_mask
,
217 gen_helper_vlbu_v_w_mask
, gen_helper_vlbu_v_d_mask
},
218 { NULL
, gen_helper_vlhu_v_h_mask
,
219 gen_helper_vlhu_v_w_mask
, gen_helper_vlhu_v_d_mask
},
221 gen_helper_vlwu_v_w_mask
, gen_helper_vlwu_v_d_mask
} },
222 /* unmasked unit stride load */
223 { { gen_helper_vlb_v_b
, gen_helper_vlb_v_h
,
224 gen_helper_vlb_v_w
, gen_helper_vlb_v_d
},
225 { NULL
, gen_helper_vlh_v_h
,
226 gen_helper_vlh_v_w
, gen_helper_vlh_v_d
},
228 gen_helper_vlw_v_w
, gen_helper_vlw_v_d
},
229 { gen_helper_vle_v_b
, gen_helper_vle_v_h
,
230 gen_helper_vle_v_w
, gen_helper_vle_v_d
},
231 { gen_helper_vlbu_v_b
, gen_helper_vlbu_v_h
,
232 gen_helper_vlbu_v_w
, gen_helper_vlbu_v_d
},
233 { NULL
, gen_helper_vlhu_v_h
,
234 gen_helper_vlhu_v_w
, gen_helper_vlhu_v_d
},
236 gen_helper_vlwu_v_w
, gen_helper_vlwu_v_d
} }
239 fn
= fns
[a
->vm
][seq
][s
->sew
];
244 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
245 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
246 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
247 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
248 return ldst_us_trans(a
->rd
, a
->rs1
, data
, fn
, s
);
251 static bool ld_us_check(DisasContext
*s
, arg_r2nfvm
* a
)
253 return (vext_check_isa_ill(s
) &&
254 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
255 vext_check_reg(s
, a
->rd
, false) &&
256 vext_check_nf(s
, a
->nf
));
259 GEN_VEXT_TRANS(vlb_v
, 0, r2nfvm
, ld_us_op
, ld_us_check
)
260 GEN_VEXT_TRANS(vlh_v
, 1, r2nfvm
, ld_us_op
, ld_us_check
)
261 GEN_VEXT_TRANS(vlw_v
, 2, r2nfvm
, ld_us_op
, ld_us_check
)
262 GEN_VEXT_TRANS(vle_v
, 3, r2nfvm
, ld_us_op
, ld_us_check
)
263 GEN_VEXT_TRANS(vlbu_v
, 4, r2nfvm
, ld_us_op
, ld_us_check
)
264 GEN_VEXT_TRANS(vlhu_v
, 5, r2nfvm
, ld_us_op
, ld_us_check
)
265 GEN_VEXT_TRANS(vlwu_v
, 6, r2nfvm
, ld_us_op
, ld_us_check
)
267 static bool st_us_op(DisasContext
*s
, arg_r2nfvm
*a
, uint8_t seq
)
270 gen_helper_ldst_us
*fn
;
271 static gen_helper_ldst_us
* const fns
[2][4][4] = {
272 /* masked unit stride load and store */
273 { { gen_helper_vsb_v_b_mask
, gen_helper_vsb_v_h_mask
,
274 gen_helper_vsb_v_w_mask
, gen_helper_vsb_v_d_mask
},
275 { NULL
, gen_helper_vsh_v_h_mask
,
276 gen_helper_vsh_v_w_mask
, gen_helper_vsh_v_d_mask
},
278 gen_helper_vsw_v_w_mask
, gen_helper_vsw_v_d_mask
},
279 { gen_helper_vse_v_b_mask
, gen_helper_vse_v_h_mask
,
280 gen_helper_vse_v_w_mask
, gen_helper_vse_v_d_mask
} },
281 /* unmasked unit stride store */
282 { { gen_helper_vsb_v_b
, gen_helper_vsb_v_h
,
283 gen_helper_vsb_v_w
, gen_helper_vsb_v_d
},
284 { NULL
, gen_helper_vsh_v_h
,
285 gen_helper_vsh_v_w
, gen_helper_vsh_v_d
},
287 gen_helper_vsw_v_w
, gen_helper_vsw_v_d
},
288 { gen_helper_vse_v_b
, gen_helper_vse_v_h
,
289 gen_helper_vse_v_w
, gen_helper_vse_v_d
} }
292 fn
= fns
[a
->vm
][seq
][s
->sew
];
297 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
298 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
299 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
300 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
301 return ldst_us_trans(a
->rd
, a
->rs1
, data
, fn
, s
);
304 static bool st_us_check(DisasContext
*s
, arg_r2nfvm
* a
)
306 return (vext_check_isa_ill(s
) &&
307 vext_check_reg(s
, a
->rd
, false) &&
308 vext_check_nf(s
, a
->nf
));
311 GEN_VEXT_TRANS(vsb_v
, 0, r2nfvm
, st_us_op
, st_us_check
)
312 GEN_VEXT_TRANS(vsh_v
, 1, r2nfvm
, st_us_op
, st_us_check
)
313 GEN_VEXT_TRANS(vsw_v
, 2, r2nfvm
, st_us_op
, st_us_check
)
314 GEN_VEXT_TRANS(vse_v
, 3, r2nfvm
, st_us_op
, st_us_check
)
317 *** stride load and store
319 typedef void gen_helper_ldst_stride(TCGv_ptr
, TCGv_ptr
, TCGv
,
320 TCGv
, TCGv_env
, TCGv_i32
);
322 static bool ldst_stride_trans(uint32_t vd
, uint32_t rs1
, uint32_t rs2
,
323 uint32_t data
, gen_helper_ldst_stride
*fn
,
330 TCGLabel
*over
= gen_new_label();
331 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
333 dest
= tcg_temp_new_ptr();
334 mask
= tcg_temp_new_ptr();
335 base
= tcg_temp_new();
336 stride
= tcg_temp_new();
337 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
339 gen_get_gpr(base
, rs1
);
340 gen_get_gpr(stride
, rs2
);
341 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
342 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
344 fn(dest
, mask
, base
, stride
, cpu_env
, desc
);
346 tcg_temp_free_ptr(dest
);
347 tcg_temp_free_ptr(mask
);
349 tcg_temp_free(stride
);
350 tcg_temp_free_i32(desc
);
355 static bool ld_stride_op(DisasContext
*s
, arg_rnfvm
*a
, uint8_t seq
)
358 gen_helper_ldst_stride
*fn
;
359 static gen_helper_ldst_stride
* const fns
[7][4] = {
360 { gen_helper_vlsb_v_b
, gen_helper_vlsb_v_h
,
361 gen_helper_vlsb_v_w
, gen_helper_vlsb_v_d
},
362 { NULL
, gen_helper_vlsh_v_h
,
363 gen_helper_vlsh_v_w
, gen_helper_vlsh_v_d
},
365 gen_helper_vlsw_v_w
, gen_helper_vlsw_v_d
},
366 { gen_helper_vlse_v_b
, gen_helper_vlse_v_h
,
367 gen_helper_vlse_v_w
, gen_helper_vlse_v_d
},
368 { gen_helper_vlsbu_v_b
, gen_helper_vlsbu_v_h
,
369 gen_helper_vlsbu_v_w
, gen_helper_vlsbu_v_d
},
370 { NULL
, gen_helper_vlshu_v_h
,
371 gen_helper_vlshu_v_w
, gen_helper_vlshu_v_d
},
373 gen_helper_vlswu_v_w
, gen_helper_vlswu_v_d
},
376 fn
= fns
[seq
][s
->sew
];
381 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
382 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
383 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
384 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
385 return ldst_stride_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
388 static bool ld_stride_check(DisasContext
*s
, arg_rnfvm
* a
)
390 return (vext_check_isa_ill(s
) &&
391 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
392 vext_check_reg(s
, a
->rd
, false) &&
393 vext_check_nf(s
, a
->nf
));
396 GEN_VEXT_TRANS(vlsb_v
, 0, rnfvm
, ld_stride_op
, ld_stride_check
)
397 GEN_VEXT_TRANS(vlsh_v
, 1, rnfvm
, ld_stride_op
, ld_stride_check
)
398 GEN_VEXT_TRANS(vlsw_v
, 2, rnfvm
, ld_stride_op
, ld_stride_check
)
399 GEN_VEXT_TRANS(vlse_v
, 3, rnfvm
, ld_stride_op
, ld_stride_check
)
400 GEN_VEXT_TRANS(vlsbu_v
, 4, rnfvm
, ld_stride_op
, ld_stride_check
)
401 GEN_VEXT_TRANS(vlshu_v
, 5, rnfvm
, ld_stride_op
, ld_stride_check
)
402 GEN_VEXT_TRANS(vlswu_v
, 6, rnfvm
, ld_stride_op
, ld_stride_check
)
404 static bool st_stride_op(DisasContext
*s
, arg_rnfvm
*a
, uint8_t seq
)
407 gen_helper_ldst_stride
*fn
;
408 static gen_helper_ldst_stride
* const fns
[4][4] = {
409 /* masked stride store */
410 { gen_helper_vssb_v_b
, gen_helper_vssb_v_h
,
411 gen_helper_vssb_v_w
, gen_helper_vssb_v_d
},
412 { NULL
, gen_helper_vssh_v_h
,
413 gen_helper_vssh_v_w
, gen_helper_vssh_v_d
},
415 gen_helper_vssw_v_w
, gen_helper_vssw_v_d
},
416 { gen_helper_vsse_v_b
, gen_helper_vsse_v_h
,
417 gen_helper_vsse_v_w
, gen_helper_vsse_v_d
}
420 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
421 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
422 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
423 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
424 fn
= fns
[seq
][s
->sew
];
429 return ldst_stride_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
432 static bool st_stride_check(DisasContext
*s
, arg_rnfvm
* a
)
434 return (vext_check_isa_ill(s
) &&
435 vext_check_reg(s
, a
->rd
, false) &&
436 vext_check_nf(s
, a
->nf
));
439 GEN_VEXT_TRANS(vssb_v
, 0, rnfvm
, st_stride_op
, st_stride_check
)
440 GEN_VEXT_TRANS(vssh_v
, 1, rnfvm
, st_stride_op
, st_stride_check
)
441 GEN_VEXT_TRANS(vssw_v
, 2, rnfvm
, st_stride_op
, st_stride_check
)
442 GEN_VEXT_TRANS(vsse_v
, 3, rnfvm
, st_stride_op
, st_stride_check
)
445 *** index load and store
447 typedef void gen_helper_ldst_index(TCGv_ptr
, TCGv_ptr
, TCGv
,
448 TCGv_ptr
, TCGv_env
, TCGv_i32
);
450 static bool ldst_index_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
,
451 uint32_t data
, gen_helper_ldst_index
*fn
,
454 TCGv_ptr dest
, mask
, index
;
458 TCGLabel
*over
= gen_new_label();
459 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
461 dest
= tcg_temp_new_ptr();
462 mask
= tcg_temp_new_ptr();
463 index
= tcg_temp_new_ptr();
464 base
= tcg_temp_new();
465 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
467 gen_get_gpr(base
, rs1
);
468 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
469 tcg_gen_addi_ptr(index
, cpu_env
, vreg_ofs(s
, vs2
));
470 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
472 fn(dest
, mask
, base
, index
, cpu_env
, desc
);
474 tcg_temp_free_ptr(dest
);
475 tcg_temp_free_ptr(mask
);
476 tcg_temp_free_ptr(index
);
478 tcg_temp_free_i32(desc
);
483 static bool ld_index_op(DisasContext
*s
, arg_rnfvm
*a
, uint8_t seq
)
486 gen_helper_ldst_index
*fn
;
487 static gen_helper_ldst_index
* const fns
[7][4] = {
488 { gen_helper_vlxb_v_b
, gen_helper_vlxb_v_h
,
489 gen_helper_vlxb_v_w
, gen_helper_vlxb_v_d
},
490 { NULL
, gen_helper_vlxh_v_h
,
491 gen_helper_vlxh_v_w
, gen_helper_vlxh_v_d
},
493 gen_helper_vlxw_v_w
, gen_helper_vlxw_v_d
},
494 { gen_helper_vlxe_v_b
, gen_helper_vlxe_v_h
,
495 gen_helper_vlxe_v_w
, gen_helper_vlxe_v_d
},
496 { gen_helper_vlxbu_v_b
, gen_helper_vlxbu_v_h
,
497 gen_helper_vlxbu_v_w
, gen_helper_vlxbu_v_d
},
498 { NULL
, gen_helper_vlxhu_v_h
,
499 gen_helper_vlxhu_v_w
, gen_helper_vlxhu_v_d
},
501 gen_helper_vlxwu_v_w
, gen_helper_vlxwu_v_d
},
504 fn
= fns
[seq
][s
->sew
];
509 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
510 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
511 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
512 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
513 return ldst_index_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
517 * For vector indexed segment loads, the destination vector register
518 * groups cannot overlap the source vector register group (specified by
519 * `vs2`), else an illegal instruction exception is raised.
521 static bool ld_index_check(DisasContext
*s
, arg_rnfvm
* a
)
523 return (vext_check_isa_ill(s
) &&
524 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
525 vext_check_reg(s
, a
->rd
, false) &&
526 vext_check_reg(s
, a
->rs2
, false) &&
527 vext_check_nf(s
, a
->nf
) &&
529 vext_check_overlap_group(a
->rd
, a
->nf
<< s
->lmul
,
530 a
->rs2
, 1 << s
->lmul
)));
533 GEN_VEXT_TRANS(vlxb_v
, 0, rnfvm
, ld_index_op
, ld_index_check
)
534 GEN_VEXT_TRANS(vlxh_v
, 1, rnfvm
, ld_index_op
, ld_index_check
)
535 GEN_VEXT_TRANS(vlxw_v
, 2, rnfvm
, ld_index_op
, ld_index_check
)
536 GEN_VEXT_TRANS(vlxe_v
, 3, rnfvm
, ld_index_op
, ld_index_check
)
537 GEN_VEXT_TRANS(vlxbu_v
, 4, rnfvm
, ld_index_op
, ld_index_check
)
538 GEN_VEXT_TRANS(vlxhu_v
, 5, rnfvm
, ld_index_op
, ld_index_check
)
539 GEN_VEXT_TRANS(vlxwu_v
, 6, rnfvm
, ld_index_op
, ld_index_check
)
541 static bool st_index_op(DisasContext
*s
, arg_rnfvm
*a
, uint8_t seq
)
544 gen_helper_ldst_index
*fn
;
545 static gen_helper_ldst_index
* const fns
[4][4] = {
546 { gen_helper_vsxb_v_b
, gen_helper_vsxb_v_h
,
547 gen_helper_vsxb_v_w
, gen_helper_vsxb_v_d
},
548 { NULL
, gen_helper_vsxh_v_h
,
549 gen_helper_vsxh_v_w
, gen_helper_vsxh_v_d
},
551 gen_helper_vsxw_v_w
, gen_helper_vsxw_v_d
},
552 { gen_helper_vsxe_v_b
, gen_helper_vsxe_v_h
,
553 gen_helper_vsxe_v_w
, gen_helper_vsxe_v_d
}
556 fn
= fns
[seq
][s
->sew
];
561 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
562 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
563 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
564 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
565 return ldst_index_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
568 static bool st_index_check(DisasContext
*s
, arg_rnfvm
* a
)
570 return (vext_check_isa_ill(s
) &&
571 vext_check_reg(s
, a
->rd
, false) &&
572 vext_check_reg(s
, a
->rs2
, false) &&
573 vext_check_nf(s
, a
->nf
));
576 GEN_VEXT_TRANS(vsxb_v
, 0, rnfvm
, st_index_op
, st_index_check
)
577 GEN_VEXT_TRANS(vsxh_v
, 1, rnfvm
, st_index_op
, st_index_check
)
578 GEN_VEXT_TRANS(vsxw_v
, 2, rnfvm
, st_index_op
, st_index_check
)
579 GEN_VEXT_TRANS(vsxe_v
, 3, rnfvm
, st_index_op
, st_index_check
)
582 *** unit stride fault-only-first load
584 static bool ldff_trans(uint32_t vd
, uint32_t rs1
, uint32_t data
,
585 gen_helper_ldst_us
*fn
, DisasContext
*s
)
591 TCGLabel
*over
= gen_new_label();
592 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
594 dest
= tcg_temp_new_ptr();
595 mask
= tcg_temp_new_ptr();
596 base
= tcg_temp_new();
597 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
599 gen_get_gpr(base
, rs1
);
600 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
601 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
603 fn(dest
, mask
, base
, cpu_env
, desc
);
605 tcg_temp_free_ptr(dest
);
606 tcg_temp_free_ptr(mask
);
608 tcg_temp_free_i32(desc
);
613 static bool ldff_op(DisasContext
*s
, arg_r2nfvm
*a
, uint8_t seq
)
616 gen_helper_ldst_us
*fn
;
617 static gen_helper_ldst_us
* const fns
[7][4] = {
618 { gen_helper_vlbff_v_b
, gen_helper_vlbff_v_h
,
619 gen_helper_vlbff_v_w
, gen_helper_vlbff_v_d
},
620 { NULL
, gen_helper_vlhff_v_h
,
621 gen_helper_vlhff_v_w
, gen_helper_vlhff_v_d
},
623 gen_helper_vlwff_v_w
, gen_helper_vlwff_v_d
},
624 { gen_helper_vleff_v_b
, gen_helper_vleff_v_h
,
625 gen_helper_vleff_v_w
, gen_helper_vleff_v_d
},
626 { gen_helper_vlbuff_v_b
, gen_helper_vlbuff_v_h
,
627 gen_helper_vlbuff_v_w
, gen_helper_vlbuff_v_d
},
628 { NULL
, gen_helper_vlhuff_v_h
,
629 gen_helper_vlhuff_v_w
, gen_helper_vlhuff_v_d
},
631 gen_helper_vlwuff_v_w
, gen_helper_vlwuff_v_d
}
634 fn
= fns
[seq
][s
->sew
];
639 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
640 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
641 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
642 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
643 return ldff_trans(a
->rd
, a
->rs1
, data
, fn
, s
);
646 GEN_VEXT_TRANS(vlbff_v
, 0, r2nfvm
, ldff_op
, ld_us_check
)
647 GEN_VEXT_TRANS(vlhff_v
, 1, r2nfvm
, ldff_op
, ld_us_check
)
648 GEN_VEXT_TRANS(vlwff_v
, 2, r2nfvm
, ldff_op
, ld_us_check
)
649 GEN_VEXT_TRANS(vleff_v
, 3, r2nfvm
, ldff_op
, ld_us_check
)
650 GEN_VEXT_TRANS(vlbuff_v
, 4, r2nfvm
, ldff_op
, ld_us_check
)
651 GEN_VEXT_TRANS(vlhuff_v
, 5, r2nfvm
, ldff_op
, ld_us_check
)
652 GEN_VEXT_TRANS(vlwuff_v
, 6, r2nfvm
, ldff_op
, ld_us_check
)
655 *** vector atomic operation
657 typedef void gen_helper_amo(TCGv_ptr
, TCGv_ptr
, TCGv
, TCGv_ptr
,
660 static bool amo_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
,
661 uint32_t data
, gen_helper_amo
*fn
, DisasContext
*s
)
663 TCGv_ptr dest
, mask
, index
;
667 TCGLabel
*over
= gen_new_label();
668 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
670 dest
= tcg_temp_new_ptr();
671 mask
= tcg_temp_new_ptr();
672 index
= tcg_temp_new_ptr();
673 base
= tcg_temp_new();
674 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
676 gen_get_gpr(base
, rs1
);
677 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
678 tcg_gen_addi_ptr(index
, cpu_env
, vreg_ofs(s
, vs2
));
679 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
681 fn(dest
, mask
, base
, index
, cpu_env
, desc
);
683 tcg_temp_free_ptr(dest
);
684 tcg_temp_free_ptr(mask
);
685 tcg_temp_free_ptr(index
);
687 tcg_temp_free_i32(desc
);
692 static bool amo_op(DisasContext
*s
, arg_rwdvm
*a
, uint8_t seq
)
696 static gen_helper_amo
*const fnsw
[9] = {
697 /* no atomic operation */
698 gen_helper_vamoswapw_v_w
,
699 gen_helper_vamoaddw_v_w
,
700 gen_helper_vamoxorw_v_w
,
701 gen_helper_vamoandw_v_w
,
702 gen_helper_vamoorw_v_w
,
703 gen_helper_vamominw_v_w
,
704 gen_helper_vamomaxw_v_w
,
705 gen_helper_vamominuw_v_w
,
706 gen_helper_vamomaxuw_v_w
708 #ifdef TARGET_RISCV64
709 static gen_helper_amo
*const fnsd
[18] = {
710 gen_helper_vamoswapw_v_d
,
711 gen_helper_vamoaddw_v_d
,
712 gen_helper_vamoxorw_v_d
,
713 gen_helper_vamoandw_v_d
,
714 gen_helper_vamoorw_v_d
,
715 gen_helper_vamominw_v_d
,
716 gen_helper_vamomaxw_v_d
,
717 gen_helper_vamominuw_v_d
,
718 gen_helper_vamomaxuw_v_d
,
719 gen_helper_vamoswapd_v_d
,
720 gen_helper_vamoaddd_v_d
,
721 gen_helper_vamoxord_v_d
,
722 gen_helper_vamoandd_v_d
,
723 gen_helper_vamoord_v_d
,
724 gen_helper_vamomind_v_d
,
725 gen_helper_vamomaxd_v_d
,
726 gen_helper_vamominud_v_d
,
727 gen_helper_vamomaxud_v_d
731 if (tb_cflags(s
->base
.tb
) & CF_PARALLEL
) {
732 gen_helper_exit_atomic(cpu_env
);
733 s
->base
.is_jmp
= DISAS_NORETURN
;
737 #ifdef TARGET_RISCV64
740 /* Check done in amo_check(). */
741 g_assert_not_reached();
744 assert(seq
< ARRAY_SIZE(fnsw
));
749 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
750 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
751 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
752 data
= FIELD_DP32(data
, VDATA
, WD
, a
->wd
);
753 return amo_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
756 * There are two rules check here.
758 * 1. SEW must be at least as wide as the AMO memory element size.
760 * 2. If SEW is greater than XLEN, an illegal instruction exception is raised.
762 static bool amo_check(DisasContext
*s
, arg_rwdvm
* a
)
764 return (!s
->vill
&& has_ext(s
, RVA
) &&
765 (!a
->wd
|| vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false)) &&
766 vext_check_reg(s
, a
->rd
, false) &&
767 vext_check_reg(s
, a
->rs2
, false) &&
768 ((1 << s
->sew
) <= sizeof(target_ulong
)) &&
769 ((1 << s
->sew
) >= 4));
772 GEN_VEXT_TRANS(vamoswapw_v
, 0, rwdvm
, amo_op
, amo_check
)
773 GEN_VEXT_TRANS(vamoaddw_v
, 1, rwdvm
, amo_op
, amo_check
)
774 GEN_VEXT_TRANS(vamoxorw_v
, 2, rwdvm
, amo_op
, amo_check
)
775 GEN_VEXT_TRANS(vamoandw_v
, 3, rwdvm
, amo_op
, amo_check
)
776 GEN_VEXT_TRANS(vamoorw_v
, 4, rwdvm
, amo_op
, amo_check
)
777 GEN_VEXT_TRANS(vamominw_v
, 5, rwdvm
, amo_op
, amo_check
)
778 GEN_VEXT_TRANS(vamomaxw_v
, 6, rwdvm
, amo_op
, amo_check
)
779 GEN_VEXT_TRANS(vamominuw_v
, 7, rwdvm
, amo_op
, amo_check
)
780 GEN_VEXT_TRANS(vamomaxuw_v
, 8, rwdvm
, amo_op
, amo_check
)
781 #ifdef TARGET_RISCV64
782 GEN_VEXT_TRANS(vamoswapd_v
, 9, rwdvm
, amo_op
, amo_check
)
783 GEN_VEXT_TRANS(vamoaddd_v
, 10, rwdvm
, amo_op
, amo_check
)
784 GEN_VEXT_TRANS(vamoxord_v
, 11, rwdvm
, amo_op
, amo_check
)
785 GEN_VEXT_TRANS(vamoandd_v
, 12, rwdvm
, amo_op
, amo_check
)
786 GEN_VEXT_TRANS(vamoord_v
, 13, rwdvm
, amo_op
, amo_check
)
787 GEN_VEXT_TRANS(vamomind_v
, 14, rwdvm
, amo_op
, amo_check
)
788 GEN_VEXT_TRANS(vamomaxd_v
, 15, rwdvm
, amo_op
, amo_check
)
789 GEN_VEXT_TRANS(vamominud_v
, 16, rwdvm
, amo_op
, amo_check
)
790 GEN_VEXT_TRANS(vamomaxud_v
, 17, rwdvm
, amo_op
, amo_check
)
794 *** Vector Integer Arithmetic Instructions
796 #define MAXSZ(s) (s->vlen >> (3 - s->lmul))
798 static bool opivv_check(DisasContext
*s
, arg_rmrr
*a
)
800 return (vext_check_isa_ill(s
) &&
801 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
802 vext_check_reg(s
, a
->rd
, false) &&
803 vext_check_reg(s
, a
->rs2
, false) &&
804 vext_check_reg(s
, a
->rs1
, false));
807 typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
808 uint32_t, uint32_t, uint32_t);
811 do_opivv_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen3Fn
*gvec_fn
,
812 gen_helper_gvec_4_ptr
*fn
)
814 TCGLabel
*over
= gen_new_label();
815 if (!opivv_check(s
, a
)) {
819 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
821 if (a
->vm
&& s
->vl_eq_vlmax
) {
822 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
),
823 vreg_ofs(s
, a
->rs2
), vreg_ofs(s
, a
->rs1
),
828 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
829 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
830 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
831 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
832 vreg_ofs(s
, a
->rs1
), vreg_ofs(s
, a
->rs2
),
833 cpu_env
, 0, s
->vlen
/ 8, data
, fn
);
839 /* OPIVV with GVEC IR */
840 #define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
841 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
843 static gen_helper_gvec_4_ptr * const fns[4] = { \
844 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
845 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
847 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
850 GEN_OPIVV_GVEC_TRANS(vadd_vv
, add
)
851 GEN_OPIVV_GVEC_TRANS(vsub_vv
, sub
)
853 typedef void gen_helper_opivx(TCGv_ptr
, TCGv_ptr
, TCGv
, TCGv_ptr
,
856 static bool opivx_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
, uint32_t vm
,
857 gen_helper_opivx
*fn
, DisasContext
*s
)
859 TCGv_ptr dest
, src2
, mask
;
864 TCGLabel
*over
= gen_new_label();
865 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
867 dest
= tcg_temp_new_ptr();
868 mask
= tcg_temp_new_ptr();
869 src2
= tcg_temp_new_ptr();
870 src1
= tcg_temp_new();
871 gen_get_gpr(src1
, rs1
);
873 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
874 data
= FIELD_DP32(data
, VDATA
, VM
, vm
);
875 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
876 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
878 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
879 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
880 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
882 fn(dest
, mask
, src1
, src2
, cpu_env
, desc
);
884 tcg_temp_free_ptr(dest
);
885 tcg_temp_free_ptr(mask
);
886 tcg_temp_free_ptr(src2
);
888 tcg_temp_free_i32(desc
);
893 static bool opivx_check(DisasContext
*s
, arg_rmrr
*a
)
895 return (vext_check_isa_ill(s
) &&
896 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
897 vext_check_reg(s
, a
->rd
, false) &&
898 vext_check_reg(s
, a
->rs2
, false));
901 typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64
,
905 do_opivx_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen2sFn
*gvec_fn
,
906 gen_helper_opivx
*fn
)
908 if (!opivx_check(s
, a
)) {
912 if (a
->vm
&& s
->vl_eq_vlmax
) {
913 TCGv_i64 src1
= tcg_temp_new_i64();
914 TCGv tmp
= tcg_temp_new();
916 gen_get_gpr(tmp
, a
->rs1
);
917 tcg_gen_ext_tl_i64(src1
, tmp
);
918 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
919 src1
, MAXSZ(s
), MAXSZ(s
));
921 tcg_temp_free_i64(src1
);
925 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
928 /* OPIVX with GVEC IR */
929 #define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
930 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
932 static gen_helper_opivx * const fns[4] = { \
933 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
934 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
936 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
939 GEN_OPIVX_GVEC_TRANS(vadd_vx
, adds
)
940 GEN_OPIVX_GVEC_TRANS(vsub_vx
, subs
)
942 static void gen_vec_rsub8_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
944 tcg_gen_vec_sub8_i64(d
, b
, a
);
947 static void gen_vec_rsub16_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
949 tcg_gen_vec_sub16_i64(d
, b
, a
);
952 static void gen_rsub_i32(TCGv_i32 ret
, TCGv_i32 arg1
, TCGv_i32 arg2
)
954 tcg_gen_sub_i32(ret
, arg2
, arg1
);
957 static void gen_rsub_i64(TCGv_i64 ret
, TCGv_i64 arg1
, TCGv_i64 arg2
)
959 tcg_gen_sub_i64(ret
, arg2
, arg1
);
962 static void gen_rsub_vec(unsigned vece
, TCGv_vec r
, TCGv_vec a
, TCGv_vec b
)
964 tcg_gen_sub_vec(vece
, r
, b
, a
);
967 static void tcg_gen_gvec_rsubs(unsigned vece
, uint32_t dofs
, uint32_t aofs
,
968 TCGv_i64 c
, uint32_t oprsz
, uint32_t maxsz
)
970 static const TCGOpcode vecop_list
[] = { INDEX_op_sub_vec
, 0 };
971 static const GVecGen2s rsub_op
[4] = {
972 { .fni8
= gen_vec_rsub8_i64
,
973 .fniv
= gen_rsub_vec
,
974 .fno
= gen_helper_vec_rsubs8
,
975 .opt_opc
= vecop_list
,
977 { .fni8
= gen_vec_rsub16_i64
,
978 .fniv
= gen_rsub_vec
,
979 .fno
= gen_helper_vec_rsubs16
,
980 .opt_opc
= vecop_list
,
982 { .fni4
= gen_rsub_i32
,
983 .fniv
= gen_rsub_vec
,
984 .fno
= gen_helper_vec_rsubs32
,
985 .opt_opc
= vecop_list
,
987 { .fni8
= gen_rsub_i64
,
988 .fniv
= gen_rsub_vec
,
989 .fno
= gen_helper_vec_rsubs64
,
990 .opt_opc
= vecop_list
,
991 .prefer_i64
= TCG_TARGET_REG_BITS
== 64,
995 tcg_debug_assert(vece
<= MO_64
);
996 tcg_gen_gvec_2s(dofs
, aofs
, oprsz
, maxsz
, c
, &rsub_op
[vece
]);
999 GEN_OPIVX_GVEC_TRANS(vrsub_vx
, rsubs
)
1001 static bool opivi_trans(uint32_t vd
, uint32_t imm
, uint32_t vs2
, uint32_t vm
,
1002 gen_helper_opivx
*fn
, DisasContext
*s
, int zx
)
1004 TCGv_ptr dest
, src2
, mask
;
1009 TCGLabel
*over
= gen_new_label();
1010 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1012 dest
= tcg_temp_new_ptr();
1013 mask
= tcg_temp_new_ptr();
1014 src2
= tcg_temp_new_ptr();
1016 src1
= tcg_const_tl(imm
);
1018 src1
= tcg_const_tl(sextract64(imm
, 0, 5));
1020 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1021 data
= FIELD_DP32(data
, VDATA
, VM
, vm
);
1022 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1023 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1025 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
1026 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
1027 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
1029 fn(dest
, mask
, src1
, src2
, cpu_env
, desc
);
1031 tcg_temp_free_ptr(dest
);
1032 tcg_temp_free_ptr(mask
);
1033 tcg_temp_free_ptr(src2
);
1034 tcg_temp_free(src1
);
1035 tcg_temp_free_i32(desc
);
1036 gen_set_label(over
);
1040 typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1041 uint32_t, uint32_t);
1044 do_opivi_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen2iFn
*gvec_fn
,
1045 gen_helper_opivx
*fn
, int zx
)
1047 if (!opivx_check(s
, a
)) {
1051 if (a
->vm
&& s
->vl_eq_vlmax
) {
1053 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1054 extract64(a
->rs1
, 0, 5), MAXSZ(s
), MAXSZ(s
));
1056 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1057 sextract64(a
->rs1
, 0, 5), MAXSZ(s
), MAXSZ(s
));
1060 return opivi_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
, zx
);
1065 /* OPIVI with GVEC IR */
1066 #define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
1067 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1069 static gen_helper_opivx * const fns[4] = { \
1070 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
1071 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
1073 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \
1077 GEN_OPIVI_GVEC_TRANS(vadd_vi
, 0, vadd_vx
, addi
)
1079 static void tcg_gen_gvec_rsubi(unsigned vece
, uint32_t dofs
, uint32_t aofs
,
1080 int64_t c
, uint32_t oprsz
, uint32_t maxsz
)
1082 TCGv_i64 tmp
= tcg_const_i64(c
);
1083 tcg_gen_gvec_rsubs(vece
, dofs
, aofs
, tmp
, oprsz
, maxsz
);
1084 tcg_temp_free_i64(tmp
);
1087 GEN_OPIVI_GVEC_TRANS(vrsub_vi
, 0, vrsub_vx
, rsubi
)
1089 /* Vector Widening Integer Add/Subtract */
1091 /* OPIVV with WIDEN */
1092 static bool opivv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1094 return (vext_check_isa_ill(s
) &&
1095 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1096 vext_check_reg(s
, a
->rd
, true) &&
1097 vext_check_reg(s
, a
->rs2
, false) &&
1098 vext_check_reg(s
, a
->rs1
, false) &&
1099 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1101 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1103 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1106 static bool do_opivv_widen(DisasContext
*s
, arg_rmrr
*a
,
1107 gen_helper_gvec_4_ptr
*fn
,
1108 bool (*checkfn
)(DisasContext
*, arg_rmrr
*))
1110 if (checkfn(s
, a
)) {
1112 TCGLabel
*over
= gen_new_label();
1113 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1115 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1116 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
1117 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1118 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
1119 vreg_ofs(s
, a
->rs1
),
1120 vreg_ofs(s
, a
->rs2
),
1121 cpu_env
, 0, s
->vlen
/ 8,
1123 gen_set_label(over
);
1129 #define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1130 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1132 static gen_helper_gvec_4_ptr * const fns[3] = { \
1133 gen_helper_##NAME##_b, \
1134 gen_helper_##NAME##_h, \
1135 gen_helper_##NAME##_w \
1137 return do_opivv_widen(s, a, fns[s->sew], CHECK); \
1140 GEN_OPIVV_WIDEN_TRANS(vwaddu_vv
, opivv_widen_check
)
1141 GEN_OPIVV_WIDEN_TRANS(vwadd_vv
, opivv_widen_check
)
1142 GEN_OPIVV_WIDEN_TRANS(vwsubu_vv
, opivv_widen_check
)
1143 GEN_OPIVV_WIDEN_TRANS(vwsub_vv
, opivv_widen_check
)
1145 /* OPIVX with WIDEN */
1146 static bool opivx_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1148 return (vext_check_isa_ill(s
) &&
1149 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1150 vext_check_reg(s
, a
->rd
, true) &&
1151 vext_check_reg(s
, a
->rs2
, false) &&
1152 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1154 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1157 static bool do_opivx_widen(DisasContext
*s
, arg_rmrr
*a
,
1158 gen_helper_opivx
*fn
)
1160 if (opivx_widen_check(s
, a
)) {
1161 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1166 #define GEN_OPIVX_WIDEN_TRANS(NAME) \
1167 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1169 static gen_helper_opivx * const fns[3] = { \
1170 gen_helper_##NAME##_b, \
1171 gen_helper_##NAME##_h, \
1172 gen_helper_##NAME##_w \
1174 return do_opivx_widen(s, a, fns[s->sew]); \
1177 GEN_OPIVX_WIDEN_TRANS(vwaddu_vx
)
1178 GEN_OPIVX_WIDEN_TRANS(vwadd_vx
)
1179 GEN_OPIVX_WIDEN_TRANS(vwsubu_vx
)
1180 GEN_OPIVX_WIDEN_TRANS(vwsub_vx
)
1182 /* WIDEN OPIVV with WIDEN */
1183 static bool opiwv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1185 return (vext_check_isa_ill(s
) &&
1186 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1187 vext_check_reg(s
, a
->rd
, true) &&
1188 vext_check_reg(s
, a
->rs2
, true) &&
1189 vext_check_reg(s
, a
->rs1
, false) &&
1190 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1192 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1195 static bool do_opiwv_widen(DisasContext
*s
, arg_rmrr
*a
,
1196 gen_helper_gvec_4_ptr
*fn
)
1198 if (opiwv_widen_check(s
, a
)) {
1200 TCGLabel
*over
= gen_new_label();
1201 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1203 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1204 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
1205 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1206 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
1207 vreg_ofs(s
, a
->rs1
),
1208 vreg_ofs(s
, a
->rs2
),
1209 cpu_env
, 0, s
->vlen
/ 8, data
, fn
);
1210 gen_set_label(over
);
1216 #define GEN_OPIWV_WIDEN_TRANS(NAME) \
1217 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1219 static gen_helper_gvec_4_ptr * const fns[3] = { \
1220 gen_helper_##NAME##_b, \
1221 gen_helper_##NAME##_h, \
1222 gen_helper_##NAME##_w \
1224 return do_opiwv_widen(s, a, fns[s->sew]); \
1227 GEN_OPIWV_WIDEN_TRANS(vwaddu_wv
)
1228 GEN_OPIWV_WIDEN_TRANS(vwadd_wv
)
1229 GEN_OPIWV_WIDEN_TRANS(vwsubu_wv
)
1230 GEN_OPIWV_WIDEN_TRANS(vwsub_wv
)
1232 /* WIDEN OPIVX with WIDEN */
1233 static bool opiwx_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1235 return (vext_check_isa_ill(s
) &&
1236 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1237 vext_check_reg(s
, a
->rd
, true) &&
1238 vext_check_reg(s
, a
->rs2
, true) &&
1239 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1242 static bool do_opiwx_widen(DisasContext
*s
, arg_rmrr
*a
,
1243 gen_helper_opivx
*fn
)
1245 if (opiwx_widen_check(s
, a
)) {
1246 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1251 #define GEN_OPIWX_WIDEN_TRANS(NAME) \
1252 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1254 static gen_helper_opivx * const fns[3] = { \
1255 gen_helper_##NAME##_b, \
1256 gen_helper_##NAME##_h, \
1257 gen_helper_##NAME##_w \
1259 return do_opiwx_widen(s, a, fns[s->sew]); \
1262 GEN_OPIWX_WIDEN_TRANS(vwaddu_wx
)
1263 GEN_OPIWX_WIDEN_TRANS(vwadd_wx
)
1264 GEN_OPIWX_WIDEN_TRANS(vwsubu_wx
)
1265 GEN_OPIWX_WIDEN_TRANS(vwsub_wx
)
1267 /* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1268 /* OPIVV without GVEC IR */
1269 #define GEN_OPIVV_TRANS(NAME, CHECK) \
1270 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1272 if (CHECK(s, a)) { \
1273 uint32_t data = 0; \
1274 static gen_helper_gvec_4_ptr * const fns[4] = { \
1275 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1276 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1278 TCGLabel *over = gen_new_label(); \
1279 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1281 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1282 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1283 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1284 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1285 vreg_ofs(s, a->rs1), \
1286 vreg_ofs(s, a->rs2), cpu_env, 0, \
1287 s->vlen / 8, data, fns[s->sew]); \
1288 gen_set_label(over); \
1295 * For vadc and vsbc, an illegal instruction exception is raised if the
1296 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1298 static bool opivv_vadc_check(DisasContext
*s
, arg_rmrr
*a
)
1300 return (vext_check_isa_ill(s
) &&
1301 vext_check_reg(s
, a
->rd
, false) &&
1302 vext_check_reg(s
, a
->rs2
, false) &&
1303 vext_check_reg(s
, a
->rs1
, false) &&
1304 ((a
->rd
!= 0) || (s
->lmul
== 0)));
1307 GEN_OPIVV_TRANS(vadc_vvm
, opivv_vadc_check
)
1308 GEN_OPIVV_TRANS(vsbc_vvm
, opivv_vadc_check
)
1311 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1312 * destination vector register overlaps a source vector register group.
1314 static bool opivv_vmadc_check(DisasContext
*s
, arg_rmrr
*a
)
1316 return (vext_check_isa_ill(s
) &&
1317 vext_check_reg(s
, a
->rs2
, false) &&
1318 vext_check_reg(s
, a
->rs1
, false) &&
1319 vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
1320 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
));
1323 GEN_OPIVV_TRANS(vmadc_vvm
, opivv_vmadc_check
)
1324 GEN_OPIVV_TRANS(vmsbc_vvm
, opivv_vmadc_check
)
1326 static bool opivx_vadc_check(DisasContext
*s
, arg_rmrr
*a
)
1328 return (vext_check_isa_ill(s
) &&
1329 vext_check_reg(s
, a
->rd
, false) &&
1330 vext_check_reg(s
, a
->rs2
, false) &&
1331 ((a
->rd
!= 0) || (s
->lmul
== 0)));
1334 /* OPIVX without GVEC IR */
1335 #define GEN_OPIVX_TRANS(NAME, CHECK) \
1336 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1338 if (CHECK(s, a)) { \
1339 static gen_helper_opivx * const fns[4] = { \
1340 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1341 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1344 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1349 GEN_OPIVX_TRANS(vadc_vxm
, opivx_vadc_check
)
1350 GEN_OPIVX_TRANS(vsbc_vxm
, opivx_vadc_check
)
1352 static bool opivx_vmadc_check(DisasContext
*s
, arg_rmrr
*a
)
1354 return (vext_check_isa_ill(s
) &&
1355 vext_check_reg(s
, a
->rs2
, false) &&
1356 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
));
1359 GEN_OPIVX_TRANS(vmadc_vxm
, opivx_vmadc_check
)
1360 GEN_OPIVX_TRANS(vmsbc_vxm
, opivx_vmadc_check
)
1362 /* OPIVI without GVEC IR */
1363 #define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \
1364 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1366 if (CHECK(s, a)) { \
1367 static gen_helper_opivx * const fns[4] = { \
1368 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
1369 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
1371 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
1372 fns[s->sew], s, ZX); \
1377 GEN_OPIVI_TRANS(vadc_vim
, 0, vadc_vxm
, opivx_vadc_check
)
1378 GEN_OPIVI_TRANS(vmadc_vim
, 0, vmadc_vxm
, opivx_vmadc_check
)
1380 /* Vector Bitwise Logical Instructions */
1381 GEN_OPIVV_GVEC_TRANS(vand_vv
, and)
1382 GEN_OPIVV_GVEC_TRANS(vor_vv
, or)
1383 GEN_OPIVV_GVEC_TRANS(vxor_vv
, xor)
1384 GEN_OPIVX_GVEC_TRANS(vand_vx
, ands
)
1385 GEN_OPIVX_GVEC_TRANS(vor_vx
, ors
)
1386 GEN_OPIVX_GVEC_TRANS(vxor_vx
, xors
)
1387 GEN_OPIVI_GVEC_TRANS(vand_vi
, 0, vand_vx
, andi
)
1388 GEN_OPIVI_GVEC_TRANS(vor_vi
, 0, vor_vx
, ori
)
1389 GEN_OPIVI_GVEC_TRANS(vxor_vi
, 0, vxor_vx
, xori
)
1391 /* Vector Single-Width Bit Shift Instructions */
1392 GEN_OPIVV_GVEC_TRANS(vsll_vv
, shlv
)
1393 GEN_OPIVV_GVEC_TRANS(vsrl_vv
, shrv
)
1394 GEN_OPIVV_GVEC_TRANS(vsra_vv
, sarv
)
1396 typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32
,
1397 uint32_t, uint32_t);
1400 do_opivx_gvec_shift(DisasContext
*s
, arg_rmrr
*a
, GVecGen2sFn32
*gvec_fn
,
1401 gen_helper_opivx
*fn
)
1403 if (!opivx_check(s
, a
)) {
1407 if (a
->vm
&& s
->vl_eq_vlmax
) {
1408 TCGv_i32 src1
= tcg_temp_new_i32();
1409 TCGv tmp
= tcg_temp_new();
1411 gen_get_gpr(tmp
, a
->rs1
);
1412 tcg_gen_trunc_tl_i32(src1
, tmp
);
1413 tcg_gen_extract_i32(src1
, src1
, 0, s
->sew
+ 3);
1414 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1415 src1
, MAXSZ(s
), MAXSZ(s
));
1417 tcg_temp_free_i32(src1
);
1421 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1424 #define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1425 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1427 static gen_helper_opivx * const fns[4] = { \
1428 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1429 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1432 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
1435 GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx
, shls
)
1436 GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx
, shrs
)
1437 GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx
, sars
)
1439 GEN_OPIVI_GVEC_TRANS(vsll_vi
, 1, vsll_vx
, shli
)
1440 GEN_OPIVI_GVEC_TRANS(vsrl_vi
, 1, vsrl_vx
, shri
)
1441 GEN_OPIVI_GVEC_TRANS(vsra_vi
, 1, vsra_vx
, sari
)
1443 /* Vector Narrowing Integer Right Shift Instructions */
1444 static bool opivv_narrow_check(DisasContext
*s
, arg_rmrr
*a
)
1446 return (vext_check_isa_ill(s
) &&
1447 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1448 vext_check_reg(s
, a
->rd
, false) &&
1449 vext_check_reg(s
, a
->rs2
, true) &&
1450 vext_check_reg(s
, a
->rs1
, false) &&
1451 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
1453 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1456 /* OPIVV with NARROW */
1457 #define GEN_OPIVV_NARROW_TRANS(NAME) \
1458 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1460 if (opivv_narrow_check(s, a)) { \
1461 uint32_t data = 0; \
1462 static gen_helper_gvec_4_ptr * const fns[3] = { \
1463 gen_helper_##NAME##_b, \
1464 gen_helper_##NAME##_h, \
1465 gen_helper_##NAME##_w, \
1467 TCGLabel *over = gen_new_label(); \
1468 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1470 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1471 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1472 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1473 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1474 vreg_ofs(s, a->rs1), \
1475 vreg_ofs(s, a->rs2), cpu_env, 0, \
1476 s->vlen / 8, data, fns[s->sew]); \
1477 gen_set_label(over); \
1482 GEN_OPIVV_NARROW_TRANS(vnsra_vv
)
1483 GEN_OPIVV_NARROW_TRANS(vnsrl_vv
)
1485 static bool opivx_narrow_check(DisasContext
*s
, arg_rmrr
*a
)
1487 return (vext_check_isa_ill(s
) &&
1488 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1489 vext_check_reg(s
, a
->rd
, false) &&
1490 vext_check_reg(s
, a
->rs2
, true) &&
1491 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
1493 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1496 /* OPIVX with NARROW */
1497 #define GEN_OPIVX_NARROW_TRANS(NAME) \
1498 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1500 if (opivx_narrow_check(s, a)) { \
1501 static gen_helper_opivx * const fns[3] = { \
1502 gen_helper_##NAME##_b, \
1503 gen_helper_##NAME##_h, \
1504 gen_helper_##NAME##_w, \
1506 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1511 GEN_OPIVX_NARROW_TRANS(vnsra_vx
)
1512 GEN_OPIVX_NARROW_TRANS(vnsrl_vx
)
1514 /* OPIVI with NARROW */
1515 #define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \
1516 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1518 if (opivx_narrow_check(s, a)) { \
1519 static gen_helper_opivx * const fns[3] = { \
1520 gen_helper_##OPIVX##_b, \
1521 gen_helper_##OPIVX##_h, \
1522 gen_helper_##OPIVX##_w, \
1524 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
1525 fns[s->sew], s, ZX); \
1530 GEN_OPIVI_NARROW_TRANS(vnsra_vi
, 1, vnsra_vx
)
1531 GEN_OPIVI_NARROW_TRANS(vnsrl_vi
, 1, vnsrl_vx
)
1533 /* Vector Integer Comparison Instructions */
1535 * For all comparison instructions, an illegal instruction exception is raised
1536 * if the destination vector register overlaps a source vector register group
1539 static bool opivv_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
1541 return (vext_check_isa_ill(s
) &&
1542 vext_check_reg(s
, a
->rs2
, false) &&
1543 vext_check_reg(s
, a
->rs1
, false) &&
1544 ((vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
1545 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
)) ||
1548 GEN_OPIVV_TRANS(vmseq_vv
, opivv_cmp_check
)
1549 GEN_OPIVV_TRANS(vmsne_vv
, opivv_cmp_check
)
1550 GEN_OPIVV_TRANS(vmsltu_vv
, opivv_cmp_check
)
1551 GEN_OPIVV_TRANS(vmslt_vv
, opivv_cmp_check
)
1552 GEN_OPIVV_TRANS(vmsleu_vv
, opivv_cmp_check
)
1553 GEN_OPIVV_TRANS(vmsle_vv
, opivv_cmp_check
)
1555 static bool opivx_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
1557 return (vext_check_isa_ill(s
) &&
1558 vext_check_reg(s
, a
->rs2
, false) &&
1559 (vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
) ||
1563 GEN_OPIVX_TRANS(vmseq_vx
, opivx_cmp_check
)
1564 GEN_OPIVX_TRANS(vmsne_vx
, opivx_cmp_check
)
1565 GEN_OPIVX_TRANS(vmsltu_vx
, opivx_cmp_check
)
1566 GEN_OPIVX_TRANS(vmslt_vx
, opivx_cmp_check
)
1567 GEN_OPIVX_TRANS(vmsleu_vx
, opivx_cmp_check
)
1568 GEN_OPIVX_TRANS(vmsle_vx
, opivx_cmp_check
)
1569 GEN_OPIVX_TRANS(vmsgtu_vx
, opivx_cmp_check
)
1570 GEN_OPIVX_TRANS(vmsgt_vx
, opivx_cmp_check
)
1572 GEN_OPIVI_TRANS(vmseq_vi
, 0, vmseq_vx
, opivx_cmp_check
)
1573 GEN_OPIVI_TRANS(vmsne_vi
, 0, vmsne_vx
, opivx_cmp_check
)
1574 GEN_OPIVI_TRANS(vmsleu_vi
, 1, vmsleu_vx
, opivx_cmp_check
)
1575 GEN_OPIVI_TRANS(vmsle_vi
, 0, vmsle_vx
, opivx_cmp_check
)
1576 GEN_OPIVI_TRANS(vmsgtu_vi
, 1, vmsgtu_vx
, opivx_cmp_check
)
1577 GEN_OPIVI_TRANS(vmsgt_vi
, 0, vmsgt_vx
, opivx_cmp_check
)
1579 /* Vector Integer Min/Max Instructions */
1580 GEN_OPIVV_GVEC_TRANS(vminu_vv
, umin
)
1581 GEN_OPIVV_GVEC_TRANS(vmin_vv
, smin
)
1582 GEN_OPIVV_GVEC_TRANS(vmaxu_vv
, umax
)
1583 GEN_OPIVV_GVEC_TRANS(vmax_vv
, smax
)
1584 GEN_OPIVX_TRANS(vminu_vx
, opivx_check
)
1585 GEN_OPIVX_TRANS(vmin_vx
, opivx_check
)
1586 GEN_OPIVX_TRANS(vmaxu_vx
, opivx_check
)
1587 GEN_OPIVX_TRANS(vmax_vx
, opivx_check
)
1589 /* Vector Single-Width Integer Multiply Instructions */
1590 GEN_OPIVV_GVEC_TRANS(vmul_vv
, mul
)
1591 GEN_OPIVV_TRANS(vmulh_vv
, opivv_check
)
1592 GEN_OPIVV_TRANS(vmulhu_vv
, opivv_check
)
1593 GEN_OPIVV_TRANS(vmulhsu_vv
, opivv_check
)
1594 GEN_OPIVX_GVEC_TRANS(vmul_vx
, muls
)
1595 GEN_OPIVX_TRANS(vmulh_vx
, opivx_check
)
1596 GEN_OPIVX_TRANS(vmulhu_vx
, opivx_check
)
1597 GEN_OPIVX_TRANS(vmulhsu_vx
, opivx_check
)
1599 /* Vector Integer Divide Instructions */
1600 GEN_OPIVV_TRANS(vdivu_vv
, opivv_check
)
1601 GEN_OPIVV_TRANS(vdiv_vv
, opivv_check
)
1602 GEN_OPIVV_TRANS(vremu_vv
, opivv_check
)
1603 GEN_OPIVV_TRANS(vrem_vv
, opivv_check
)
1604 GEN_OPIVX_TRANS(vdivu_vx
, opivx_check
)
1605 GEN_OPIVX_TRANS(vdiv_vx
, opivx_check
)
1606 GEN_OPIVX_TRANS(vremu_vx
, opivx_check
)
1607 GEN_OPIVX_TRANS(vrem_vx
, opivx_check
)
1609 /* Vector Widening Integer Multiply Instructions */
1610 GEN_OPIVV_WIDEN_TRANS(vwmul_vv
, opivv_widen_check
)
1611 GEN_OPIVV_WIDEN_TRANS(vwmulu_vv
, opivv_widen_check
)
1612 GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv
, opivv_widen_check
)
1613 GEN_OPIVX_WIDEN_TRANS(vwmul_vx
)
1614 GEN_OPIVX_WIDEN_TRANS(vwmulu_vx
)
1615 GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx
)
1617 /* Vector Single-Width Integer Multiply-Add Instructions */
1618 GEN_OPIVV_TRANS(vmacc_vv
, opivv_check
)
1619 GEN_OPIVV_TRANS(vnmsac_vv
, opivv_check
)
1620 GEN_OPIVV_TRANS(vmadd_vv
, opivv_check
)
1621 GEN_OPIVV_TRANS(vnmsub_vv
, opivv_check
)
1622 GEN_OPIVX_TRANS(vmacc_vx
, opivx_check
)
1623 GEN_OPIVX_TRANS(vnmsac_vx
, opivx_check
)
1624 GEN_OPIVX_TRANS(vmadd_vx
, opivx_check
)
1625 GEN_OPIVX_TRANS(vnmsub_vx
, opivx_check
)
1627 /* Vector Widening Integer Multiply-Add Instructions */
1628 GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv
, opivv_widen_check
)
1629 GEN_OPIVV_WIDEN_TRANS(vwmacc_vv
, opivv_widen_check
)
1630 GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv
, opivv_widen_check
)
1631 GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx
)
1632 GEN_OPIVX_WIDEN_TRANS(vwmacc_vx
)
1633 GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx
)
1634 GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx
)
1636 /* Vector Integer Merge and Move Instructions */
1637 static bool trans_vmv_v_v(DisasContext
*s
, arg_vmv_v_v
*a
)
1639 if (vext_check_isa_ill(s
) &&
1640 vext_check_reg(s
, a
->rd
, false) &&
1641 vext_check_reg(s
, a
->rs1
, false)) {
1643 if (s
->vl_eq_vlmax
) {
1644 tcg_gen_gvec_mov(s
->sew
, vreg_ofs(s
, a
->rd
),
1645 vreg_ofs(s
, a
->rs1
),
1646 MAXSZ(s
), MAXSZ(s
));
1648 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1649 static gen_helper_gvec_2_ptr
* const fns
[4] = {
1650 gen_helper_vmv_v_v_b
, gen_helper_vmv_v_v_h
,
1651 gen_helper_vmv_v_v_w
, gen_helper_vmv_v_v_d
,
1653 TCGLabel
*over
= gen_new_label();
1654 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1656 tcg_gen_gvec_2_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs1
),
1657 cpu_env
, 0, s
->vlen
/ 8, data
, fns
[s
->sew
]);
1658 gen_set_label(over
);
1665 typedef void gen_helper_vmv_vx(TCGv_ptr
, TCGv_i64
, TCGv_env
, TCGv_i32
);
1666 static bool trans_vmv_v_x(DisasContext
*s
, arg_vmv_v_x
*a
)
1668 if (vext_check_isa_ill(s
) &&
1669 vext_check_reg(s
, a
->rd
, false)) {
1672 TCGLabel
*over
= gen_new_label();
1673 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1675 s1
= tcg_temp_new();
1676 gen_get_gpr(s1
, a
->rs1
);
1678 if (s
->vl_eq_vlmax
) {
1679 tcg_gen_gvec_dup_tl(s
->sew
, vreg_ofs(s
, a
->rd
),
1680 MAXSZ(s
), MAXSZ(s
), s1
);
1683 TCGv_i64 s1_i64
= tcg_temp_new_i64();
1684 TCGv_ptr dest
= tcg_temp_new_ptr();
1685 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1686 static gen_helper_vmv_vx
* const fns
[4] = {
1687 gen_helper_vmv_v_x_b
, gen_helper_vmv_v_x_h
,
1688 gen_helper_vmv_v_x_w
, gen_helper_vmv_v_x_d
,
1691 tcg_gen_ext_tl_i64(s1_i64
, s1
);
1692 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1693 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
1694 fns
[s
->sew
](dest
, s1_i64
, cpu_env
, desc
);
1696 tcg_temp_free_ptr(dest
);
1697 tcg_temp_free_i32(desc
);
1698 tcg_temp_free_i64(s1_i64
);
1702 gen_set_label(over
);
1708 static bool trans_vmv_v_i(DisasContext
*s
, arg_vmv_v_i
*a
)
1710 if (vext_check_isa_ill(s
) &&
1711 vext_check_reg(s
, a
->rd
, false)) {
1713 int64_t simm
= sextract64(a
->rs1
, 0, 5);
1714 if (s
->vl_eq_vlmax
) {
1715 tcg_gen_gvec_dup_imm(s
->sew
, vreg_ofs(s
, a
->rd
),
1716 MAXSZ(s
), MAXSZ(s
), simm
);
1721 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1722 static gen_helper_vmv_vx
* const fns
[4] = {
1723 gen_helper_vmv_v_x_b
, gen_helper_vmv_v_x_h
,
1724 gen_helper_vmv_v_x_w
, gen_helper_vmv_v_x_d
,
1726 TCGLabel
*over
= gen_new_label();
1727 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1729 s1
= tcg_const_i64(simm
);
1730 dest
= tcg_temp_new_ptr();
1731 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1732 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
1733 fns
[s
->sew
](dest
, s1
, cpu_env
, desc
);
1735 tcg_temp_free_ptr(dest
);
1736 tcg_temp_free_i32(desc
);
1737 tcg_temp_free_i64(s1
);
1738 gen_set_label(over
);
1745 GEN_OPIVV_TRANS(vmerge_vvm
, opivv_vadc_check
)
1746 GEN_OPIVX_TRANS(vmerge_vxm
, opivx_vadc_check
)
1747 GEN_OPIVI_TRANS(vmerge_vim
, 0, vmerge_vxm
, opivx_vadc_check
)
1750 *** Vector Fixed-Point Arithmetic Instructions
1753 /* Vector Single-Width Saturating Add and Subtract */
1754 GEN_OPIVV_TRANS(vsaddu_vv
, opivv_check
)
1755 GEN_OPIVV_TRANS(vsadd_vv
, opivv_check
)
1756 GEN_OPIVV_TRANS(vssubu_vv
, opivv_check
)
1757 GEN_OPIVV_TRANS(vssub_vv
, opivv_check
)
1758 GEN_OPIVX_TRANS(vsaddu_vx
, opivx_check
)
1759 GEN_OPIVX_TRANS(vsadd_vx
, opivx_check
)
1760 GEN_OPIVX_TRANS(vssubu_vx
, opivx_check
)
1761 GEN_OPIVX_TRANS(vssub_vx
, opivx_check
)
1762 GEN_OPIVI_TRANS(vsaddu_vi
, 1, vsaddu_vx
, opivx_check
)
1763 GEN_OPIVI_TRANS(vsadd_vi
, 0, vsadd_vx
, opivx_check
)
1765 /* Vector Single-Width Averaging Add and Subtract */
1766 GEN_OPIVV_TRANS(vaadd_vv
, opivv_check
)
1767 GEN_OPIVV_TRANS(vasub_vv
, opivv_check
)
1768 GEN_OPIVX_TRANS(vaadd_vx
, opivx_check
)
1769 GEN_OPIVX_TRANS(vasub_vx
, opivx_check
)
1770 GEN_OPIVI_TRANS(vaadd_vi
, 0, vaadd_vx
, opivx_check
)
1772 /* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1773 GEN_OPIVV_TRANS(vsmul_vv
, opivv_check
)
1774 GEN_OPIVX_TRANS(vsmul_vx
, opivx_check
)
1776 /* Vector Widening Saturating Scaled Multiply-Add */
1777 GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv
, opivv_widen_check
)
1778 GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv
, opivv_widen_check
)
1779 GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv
, opivv_widen_check
)
1780 GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx
)
1781 GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx
)
1782 GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx
)
1783 GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx
)
1785 /* Vector Single-Width Scaling Shift Instructions */
1786 GEN_OPIVV_TRANS(vssrl_vv
, opivv_check
)
1787 GEN_OPIVV_TRANS(vssra_vv
, opivv_check
)
1788 GEN_OPIVX_TRANS(vssrl_vx
, opivx_check
)
1789 GEN_OPIVX_TRANS(vssra_vx
, opivx_check
)
1790 GEN_OPIVI_TRANS(vssrl_vi
, 1, vssrl_vx
, opivx_check
)
1791 GEN_OPIVI_TRANS(vssra_vi
, 0, vssra_vx
, opivx_check
)
1793 /* Vector Narrowing Fixed-Point Clip Instructions */
1794 GEN_OPIVV_NARROW_TRANS(vnclipu_vv
)
1795 GEN_OPIVV_NARROW_TRANS(vnclip_vv
)
1796 GEN_OPIVX_NARROW_TRANS(vnclipu_vx
)
1797 GEN_OPIVX_NARROW_TRANS(vnclip_vx
)
1798 GEN_OPIVI_NARROW_TRANS(vnclipu_vi
, 1, vnclipu_vx
)
1799 GEN_OPIVI_NARROW_TRANS(vnclip_vi
, 1, vnclip_vx
)
1802 *** Vector Float Point Arithmetic Instructions
1804 /* Vector Single-Width Floating-Point Add/Subtract Instructions */
1807 * If the current SEW does not correspond to a supported IEEE floating-point
1808 * type, an illegal instruction exception is raised.
1810 static bool opfvv_check(DisasContext
*s
, arg_rmrr
*a
)
1812 return (vext_check_isa_ill(s
) &&
1813 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1814 vext_check_reg(s
, a
->rd
, false) &&
1815 vext_check_reg(s
, a
->rs2
, false) &&
1816 vext_check_reg(s
, a
->rs1
, false) &&
1820 /* OPFVV without GVEC IR */
1821 #define GEN_OPFVV_TRANS(NAME, CHECK) \
1822 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1824 if (CHECK(s, a)) { \
1825 uint32_t data = 0; \
1826 static gen_helper_gvec_4_ptr * const fns[3] = { \
1827 gen_helper_##NAME##_h, \
1828 gen_helper_##NAME##_w, \
1829 gen_helper_##NAME##_d, \
1831 TCGLabel *over = gen_new_label(); \
1833 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1835 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1836 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1837 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1838 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1839 vreg_ofs(s, a->rs1), \
1840 vreg_ofs(s, a->rs2), cpu_env, 0, \
1841 s->vlen / 8, data, fns[s->sew - 1]); \
1842 gen_set_label(over); \
1847 GEN_OPFVV_TRANS(vfadd_vv
, opfvv_check
)
1848 GEN_OPFVV_TRANS(vfsub_vv
, opfvv_check
)
1850 typedef void gen_helper_opfvf(TCGv_ptr
, TCGv_ptr
, TCGv_i64
, TCGv_ptr
,
1851 TCGv_env
, TCGv_i32
);
1853 static bool opfvf_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
,
1854 uint32_t data
, gen_helper_opfvf
*fn
, DisasContext
*s
)
1856 TCGv_ptr dest
, src2
, mask
;
1859 TCGLabel
*over
= gen_new_label();
1860 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1862 dest
= tcg_temp_new_ptr();
1863 mask
= tcg_temp_new_ptr();
1864 src2
= tcg_temp_new_ptr();
1865 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1867 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
1868 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
1869 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
1871 fn(dest
, mask
, cpu_fpr
[rs1
], src2
, cpu_env
, desc
);
1873 tcg_temp_free_ptr(dest
);
1874 tcg_temp_free_ptr(mask
);
1875 tcg_temp_free_ptr(src2
);
1876 tcg_temp_free_i32(desc
);
1877 gen_set_label(over
);
1881 static bool opfvf_check(DisasContext
*s
, arg_rmrr
*a
)
1884 * If the current SEW does not correspond to a supported IEEE floating-point
1885 * type, an illegal instruction exception is raised
1887 return (vext_check_isa_ill(s
) &&
1888 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1889 vext_check_reg(s
, a
->rd
, false) &&
1890 vext_check_reg(s
, a
->rs2
, false) &&
1894 /* OPFVF without GVEC IR */
1895 #define GEN_OPFVF_TRANS(NAME, CHECK) \
1896 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1898 if (CHECK(s, a)) { \
1899 uint32_t data = 0; \
1900 static gen_helper_opfvf *const fns[3] = { \
1901 gen_helper_##NAME##_h, \
1902 gen_helper_##NAME##_w, \
1903 gen_helper_##NAME##_d, \
1906 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1907 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1908 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1909 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
1910 fns[s->sew - 1], s); \
1915 GEN_OPFVF_TRANS(vfadd_vf
, opfvf_check
)
1916 GEN_OPFVF_TRANS(vfsub_vf
, opfvf_check
)
1917 GEN_OPFVF_TRANS(vfrsub_vf
, opfvf_check
)
1919 /* Vector Widening Floating-Point Add/Subtract Instructions */
1920 static bool opfvv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1922 return (vext_check_isa_ill(s
) &&
1923 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1924 vext_check_reg(s
, a
->rd
, true) &&
1925 vext_check_reg(s
, a
->rs2
, false) &&
1926 vext_check_reg(s
, a
->rs1
, false) &&
1927 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1929 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1931 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
1934 /* OPFVV with WIDEN */
1935 #define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
1936 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1938 if (CHECK(s, a)) { \
1939 uint32_t data = 0; \
1940 static gen_helper_gvec_4_ptr * const fns[2] = { \
1941 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
1943 TCGLabel *over = gen_new_label(); \
1945 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1947 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1948 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1949 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1950 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1951 vreg_ofs(s, a->rs1), \
1952 vreg_ofs(s, a->rs2), cpu_env, 0, \
1953 s->vlen / 8, data, fns[s->sew - 1]); \
1954 gen_set_label(over); \
1960 GEN_OPFVV_WIDEN_TRANS(vfwadd_vv
, opfvv_widen_check
)
1961 GEN_OPFVV_WIDEN_TRANS(vfwsub_vv
, opfvv_widen_check
)
1963 static bool opfvf_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1965 return (vext_check_isa_ill(s
) &&
1966 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1967 vext_check_reg(s
, a
->rd
, true) &&
1968 vext_check_reg(s
, a
->rs2
, false) &&
1969 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1971 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
1974 /* OPFVF with WIDEN */
1975 #define GEN_OPFVF_WIDEN_TRANS(NAME) \
1976 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1978 if (opfvf_widen_check(s, a)) { \
1979 uint32_t data = 0; \
1980 static gen_helper_opfvf *const fns[2] = { \
1981 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
1984 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1985 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1986 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1987 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
1988 fns[s->sew - 1], s); \
1993 GEN_OPFVF_WIDEN_TRANS(vfwadd_vf
)
1994 GEN_OPFVF_WIDEN_TRANS(vfwsub_vf
)
1996 static bool opfwv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1998 return (vext_check_isa_ill(s
) &&
1999 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2000 vext_check_reg(s
, a
->rd
, true) &&
2001 vext_check_reg(s
, a
->rs2
, true) &&
2002 vext_check_reg(s
, a
->rs1
, false) &&
2003 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
2005 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2008 /* WIDEN OPFVV with WIDEN */
2009 #define GEN_OPFWV_WIDEN_TRANS(NAME) \
2010 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
2012 if (opfwv_widen_check(s, a)) { \
2013 uint32_t data = 0; \
2014 static gen_helper_gvec_4_ptr * const fns[2] = { \
2015 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
2017 TCGLabel *over = gen_new_label(); \
2019 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2021 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2022 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2023 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2024 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2025 vreg_ofs(s, a->rs1), \
2026 vreg_ofs(s, a->rs2), cpu_env, 0, \
2027 s->vlen / 8, data, fns[s->sew - 1]); \
2028 gen_set_label(over); \
2034 GEN_OPFWV_WIDEN_TRANS(vfwadd_wv
)
2035 GEN_OPFWV_WIDEN_TRANS(vfwsub_wv
)
2037 static bool opfwf_widen_check(DisasContext
*s
, arg_rmrr
*a
)
2039 return (vext_check_isa_ill(s
) &&
2040 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2041 vext_check_reg(s
, a
->rd
, true) &&
2042 vext_check_reg(s
, a
->rs2
, true) &&
2043 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2046 /* WIDEN OPFVF with WIDEN */
2047 #define GEN_OPFWF_WIDEN_TRANS(NAME) \
2048 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
2050 if (opfwf_widen_check(s, a)) { \
2051 uint32_t data = 0; \
2052 static gen_helper_opfvf *const fns[2] = { \
2053 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
2056 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2057 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2058 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2059 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
2060 fns[s->sew - 1], s); \
2065 GEN_OPFWF_WIDEN_TRANS(vfwadd_wf
)
2066 GEN_OPFWF_WIDEN_TRANS(vfwsub_wf
)
2068 /* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2069 GEN_OPFVV_TRANS(vfmul_vv
, opfvv_check
)
2070 GEN_OPFVV_TRANS(vfdiv_vv
, opfvv_check
)
2071 GEN_OPFVF_TRANS(vfmul_vf
, opfvf_check
)
2072 GEN_OPFVF_TRANS(vfdiv_vf
, opfvf_check
)
2073 GEN_OPFVF_TRANS(vfrdiv_vf
, opfvf_check
)
2075 /* Vector Widening Floating-Point Multiply */
2076 GEN_OPFVV_WIDEN_TRANS(vfwmul_vv
, opfvv_widen_check
)
2077 GEN_OPFVF_WIDEN_TRANS(vfwmul_vf
)
2079 /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2080 GEN_OPFVV_TRANS(vfmacc_vv
, opfvv_check
)
2081 GEN_OPFVV_TRANS(vfnmacc_vv
, opfvv_check
)
2082 GEN_OPFVV_TRANS(vfmsac_vv
, opfvv_check
)
2083 GEN_OPFVV_TRANS(vfnmsac_vv
, opfvv_check
)
2084 GEN_OPFVV_TRANS(vfmadd_vv
, opfvv_check
)
2085 GEN_OPFVV_TRANS(vfnmadd_vv
, opfvv_check
)
2086 GEN_OPFVV_TRANS(vfmsub_vv
, opfvv_check
)
2087 GEN_OPFVV_TRANS(vfnmsub_vv
, opfvv_check
)
2088 GEN_OPFVF_TRANS(vfmacc_vf
, opfvf_check
)
2089 GEN_OPFVF_TRANS(vfnmacc_vf
, opfvf_check
)
2090 GEN_OPFVF_TRANS(vfmsac_vf
, opfvf_check
)
2091 GEN_OPFVF_TRANS(vfnmsac_vf
, opfvf_check
)
2092 GEN_OPFVF_TRANS(vfmadd_vf
, opfvf_check
)
2093 GEN_OPFVF_TRANS(vfnmadd_vf
, opfvf_check
)
2094 GEN_OPFVF_TRANS(vfmsub_vf
, opfvf_check
)
2095 GEN_OPFVF_TRANS(vfnmsub_vf
, opfvf_check
)
2097 /* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2098 GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv
, opfvv_widen_check
)
2099 GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv
, opfvv_widen_check
)
2100 GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv
, opfvv_widen_check
)
2101 GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv
, opfvv_widen_check
)
2102 GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf
)
2103 GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf
)
2104 GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf
)
2105 GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf
)
2107 /* Vector Floating-Point Square-Root Instruction */
2110 * If the current SEW does not correspond to a supported IEEE floating-point
2111 * type, an illegal instruction exception is raised
2113 static bool opfv_check(DisasContext
*s
, arg_rmr
*a
)
2115 return (vext_check_isa_ill(s
) &&
2116 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
2117 vext_check_reg(s
, a
->rd
, false) &&
2118 vext_check_reg(s
, a
->rs2
, false) &&
2122 #define GEN_OPFV_TRANS(NAME, CHECK) \
2123 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2125 if (CHECK(s, a)) { \
2126 uint32_t data = 0; \
2127 static gen_helper_gvec_3_ptr * const fns[3] = { \
2128 gen_helper_##NAME##_h, \
2129 gen_helper_##NAME##_w, \
2130 gen_helper_##NAME##_d, \
2132 TCGLabel *over = gen_new_label(); \
2134 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2136 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2137 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2138 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2139 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2140 vreg_ofs(s, a->rs2), cpu_env, 0, \
2141 s->vlen / 8, data, fns[s->sew - 1]); \
2142 gen_set_label(over); \
2148 GEN_OPFV_TRANS(vfsqrt_v
, opfv_check
)
2150 /* Vector Floating-Point MIN/MAX Instructions */
2151 GEN_OPFVV_TRANS(vfmin_vv
, opfvv_check
)
2152 GEN_OPFVV_TRANS(vfmax_vv
, opfvv_check
)
2153 GEN_OPFVF_TRANS(vfmin_vf
, opfvf_check
)
2154 GEN_OPFVF_TRANS(vfmax_vf
, opfvf_check
)
2156 /* Vector Floating-Point Sign-Injection Instructions */
2157 GEN_OPFVV_TRANS(vfsgnj_vv
, opfvv_check
)
2158 GEN_OPFVV_TRANS(vfsgnjn_vv
, opfvv_check
)
2159 GEN_OPFVV_TRANS(vfsgnjx_vv
, opfvv_check
)
2160 GEN_OPFVF_TRANS(vfsgnj_vf
, opfvf_check
)
2161 GEN_OPFVF_TRANS(vfsgnjn_vf
, opfvf_check
)
2162 GEN_OPFVF_TRANS(vfsgnjx_vf
, opfvf_check
)
2164 /* Vector Floating-Point Compare Instructions */
2165 static bool opfvv_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
2167 return (vext_check_isa_ill(s
) &&
2168 vext_check_reg(s
, a
->rs2
, false) &&
2169 vext_check_reg(s
, a
->rs1
, false) &&
2171 ((vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
2172 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
)) ||
2176 GEN_OPFVV_TRANS(vmfeq_vv
, opfvv_cmp_check
)
2177 GEN_OPFVV_TRANS(vmfne_vv
, opfvv_cmp_check
)
2178 GEN_OPFVV_TRANS(vmflt_vv
, opfvv_cmp_check
)
2179 GEN_OPFVV_TRANS(vmfle_vv
, opfvv_cmp_check
)
2180 GEN_OPFVV_TRANS(vmford_vv
, opfvv_cmp_check
)
2182 static bool opfvf_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
2184 return (vext_check_isa_ill(s
) &&
2185 vext_check_reg(s
, a
->rs2
, false) &&
2187 (vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
) ||
2191 GEN_OPFVF_TRANS(vmfeq_vf
, opfvf_cmp_check
)
2192 GEN_OPFVF_TRANS(vmfne_vf
, opfvf_cmp_check
)
2193 GEN_OPFVF_TRANS(vmflt_vf
, opfvf_cmp_check
)
2194 GEN_OPFVF_TRANS(vmfle_vf
, opfvf_cmp_check
)
2195 GEN_OPFVF_TRANS(vmfgt_vf
, opfvf_cmp_check
)
2196 GEN_OPFVF_TRANS(vmfge_vf
, opfvf_cmp_check
)
2197 GEN_OPFVF_TRANS(vmford_vf
, opfvf_cmp_check
)
2199 /* Vector Floating-Point Classify Instruction */
2200 GEN_OPFV_TRANS(vfclass_v
, opfv_check
)
2202 /* Vector Floating-Point Merge Instruction */
2203 GEN_OPFVF_TRANS(vfmerge_vfm
, opfvf_check
)
2205 static bool trans_vfmv_v_f(DisasContext
*s
, arg_vfmv_v_f
*a
)
2207 if (vext_check_isa_ill(s
) &&
2208 vext_check_reg(s
, a
->rd
, false) &&
2211 if (s
->vl_eq_vlmax
) {
2212 tcg_gen_gvec_dup_i64(s
->sew
, vreg_ofs(s
, a
->rd
),
2213 MAXSZ(s
), MAXSZ(s
), cpu_fpr
[a
->rs1
]);
2217 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
2218 static gen_helper_vmv_vx
* const fns
[3] = {
2219 gen_helper_vmv_v_x_h
,
2220 gen_helper_vmv_v_x_w
,
2221 gen_helper_vmv_v_x_d
,
2223 TCGLabel
*over
= gen_new_label();
2224 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2226 dest
= tcg_temp_new_ptr();
2227 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
2228 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
2229 fns
[s
->sew
- 1](dest
, cpu_fpr
[a
->rs1
], cpu_env
, desc
);
2231 tcg_temp_free_ptr(dest
);
2232 tcg_temp_free_i32(desc
);
2233 gen_set_label(over
);
2240 /* Single-Width Floating-Point/Integer Type-Convert Instructions */
2241 GEN_OPFV_TRANS(vfcvt_xu_f_v
, opfv_check
)
2242 GEN_OPFV_TRANS(vfcvt_x_f_v
, opfv_check
)
2243 GEN_OPFV_TRANS(vfcvt_f_xu_v
, opfv_check
)
2244 GEN_OPFV_TRANS(vfcvt_f_x_v
, opfv_check
)
2246 /* Widening Floating-Point/Integer Type-Convert Instructions */
2249 * If the current SEW does not correspond to a supported IEEE floating-point
2250 * type, an illegal instruction exception is raised
2252 static bool opfv_widen_check(DisasContext
*s
, arg_rmr
*a
)
2254 return (vext_check_isa_ill(s
) &&
2255 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2256 vext_check_reg(s
, a
->rd
, true) &&
2257 vext_check_reg(s
, a
->rs2
, false) &&
2258 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
2260 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2263 #define GEN_OPFV_WIDEN_TRANS(NAME) \
2264 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2266 if (opfv_widen_check(s, a)) { \
2267 uint32_t data = 0; \
2268 static gen_helper_gvec_3_ptr * const fns[2] = { \
2269 gen_helper_##NAME##_h, \
2270 gen_helper_##NAME##_w, \
2272 TCGLabel *over = gen_new_label(); \
2274 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2276 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2277 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2278 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2279 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2280 vreg_ofs(s, a->rs2), cpu_env, 0, \
2281 s->vlen / 8, data, fns[s->sew - 1]); \
2282 gen_set_label(over); \
2288 GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v
)
2289 GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v
)
2290 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v
)
2291 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v
)
2292 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v
)
2294 /* Narrowing Floating-Point/Integer Type-Convert Instructions */
2297 * If the current SEW does not correspond to a supported IEEE floating-point
2298 * type, an illegal instruction exception is raised
2300 static bool opfv_narrow_check(DisasContext
*s
, arg_rmr
*a
)
2302 return (vext_check_isa_ill(s
) &&
2303 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
2304 vext_check_reg(s
, a
->rd
, false) &&
2305 vext_check_reg(s
, a
->rs2
, true) &&
2306 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
2308 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2311 #define GEN_OPFV_NARROW_TRANS(NAME) \
2312 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2314 if (opfv_narrow_check(s, a)) { \
2315 uint32_t data = 0; \
2316 static gen_helper_gvec_3_ptr * const fns[2] = { \
2317 gen_helper_##NAME##_h, \
2318 gen_helper_##NAME##_w, \
2320 TCGLabel *over = gen_new_label(); \
2322 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2324 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2325 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2326 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2327 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2328 vreg_ofs(s, a->rs2), cpu_env, 0, \
2329 s->vlen / 8, data, fns[s->sew - 1]); \
2330 gen_set_label(over); \
2336 GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v
)
2337 GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v
)
2338 GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v
)
2339 GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v
)
2340 GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v
)
2343 *** Vector Reduction Operations
2345 /* Vector Single-Width Integer Reduction Instructions */
2346 static bool reduction_check(DisasContext
*s
, arg_rmrr
*a
)
2348 return vext_check_isa_ill(s
) && vext_check_reg(s
, a
->rs2
, false);
2351 GEN_OPIVV_TRANS(vredsum_vs
, reduction_check
)
2352 GEN_OPIVV_TRANS(vredmaxu_vs
, reduction_check
)
2353 GEN_OPIVV_TRANS(vredmax_vs
, reduction_check
)
2354 GEN_OPIVV_TRANS(vredminu_vs
, reduction_check
)
2355 GEN_OPIVV_TRANS(vredmin_vs
, reduction_check
)
2356 GEN_OPIVV_TRANS(vredand_vs
, reduction_check
)
2357 GEN_OPIVV_TRANS(vredor_vs
, reduction_check
)
2358 GEN_OPIVV_TRANS(vredxor_vs
, reduction_check
)
2360 /* Vector Widening Integer Reduction Instructions */
2361 GEN_OPIVV_WIDEN_TRANS(vwredsum_vs
, reduction_check
)
2362 GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs
, reduction_check
)
2364 /* Vector Single-Width Floating-Point Reduction Instructions */
2365 GEN_OPFVV_TRANS(vfredsum_vs
, reduction_check
)
2366 GEN_OPFVV_TRANS(vfredmax_vs
, reduction_check
)
2367 GEN_OPFVV_TRANS(vfredmin_vs
, reduction_check
)
2369 /* Vector Widening Floating-Point Reduction Instructions */
2370 GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs
, reduction_check
)
2373 *** Vector Mask Operations
2376 /* Vector Mask-Register Logical Instructions */
2377 #define GEN_MM_TRANS(NAME) \
2378 static bool trans_##NAME(DisasContext *s, arg_r *a) \
2380 if (vext_check_isa_ill(s)) { \
2381 uint32_t data = 0; \
2382 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \
2383 TCGLabel *over = gen_new_label(); \
2384 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2386 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2387 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2388 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2389 vreg_ofs(s, a->rs1), \
2390 vreg_ofs(s, a->rs2), cpu_env, 0, \
2391 s->vlen / 8, data, fn); \
2392 gen_set_label(over); \
2398 GEN_MM_TRANS(vmand_mm
)
2399 GEN_MM_TRANS(vmnand_mm
)
2400 GEN_MM_TRANS(vmandnot_mm
)
2401 GEN_MM_TRANS(vmxor_mm
)
2402 GEN_MM_TRANS(vmor_mm
)
2403 GEN_MM_TRANS(vmnor_mm
)
2404 GEN_MM_TRANS(vmornot_mm
)
2405 GEN_MM_TRANS(vmxnor_mm
)
2407 /* Vector mask population count vmpopc */
2408 static bool trans_vmpopc_m(DisasContext
*s
, arg_rmr
*a
)
2410 if (vext_check_isa_ill(s
)) {
2411 TCGv_ptr src2
, mask
;
2415 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
2416 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
2417 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
2419 mask
= tcg_temp_new_ptr();
2420 src2
= tcg_temp_new_ptr();
2421 dst
= tcg_temp_new();
2422 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
2424 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, a
->rs2
));
2425 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
2427 gen_helper_vmpopc_m(dst
, mask
, src2
, cpu_env
, desc
);
2428 gen_set_gpr(a
->rd
, dst
);
2430 tcg_temp_free_ptr(mask
);
2431 tcg_temp_free_ptr(src2
);
2433 tcg_temp_free_i32(desc
);
2439 /* vmfirst find-first-set mask bit */
2440 static bool trans_vmfirst_m(DisasContext
*s
, arg_rmr
*a
)
2442 if (vext_check_isa_ill(s
)) {
2443 TCGv_ptr src2
, mask
;
2447 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
2448 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
2449 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
2451 mask
= tcg_temp_new_ptr();
2452 src2
= tcg_temp_new_ptr();
2453 dst
= tcg_temp_new();
2454 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
2456 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, a
->rs2
));
2457 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
2459 gen_helper_vmfirst_m(dst
, mask
, src2
, cpu_env
, desc
);
2460 gen_set_gpr(a
->rd
, dst
);
2462 tcg_temp_free_ptr(mask
);
2463 tcg_temp_free_ptr(src2
);
2465 tcg_temp_free_i32(desc
);
2471 /* vmsbf.m set-before-first mask bit */
2472 /* vmsif.m set-includ-first mask bit */
2473 /* vmsof.m set-only-first mask bit */
2474 #define GEN_M_TRANS(NAME) \
2475 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2477 if (vext_check_isa_ill(s)) { \
2478 uint32_t data = 0; \
2479 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \
2480 TCGLabel *over = gen_new_label(); \
2481 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2483 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2484 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2485 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2486 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \
2487 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \
2488 cpu_env, 0, s->vlen / 8, data, fn); \
2489 gen_set_label(over); \
2495 GEN_M_TRANS(vmsbf_m
)
2496 GEN_M_TRANS(vmsif_m
)
2497 GEN_M_TRANS(vmsof_m
)
2499 /* Vector Iota Instruction */
2500 static bool trans_viota_m(DisasContext
*s
, arg_viota_m
*a
)
2502 if (vext_check_isa_ill(s
) &&
2503 vext_check_reg(s
, a
->rd
, false) &&
2504 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
, 1) &&
2505 (a
->vm
!= 0 || a
->rd
!= 0)) {
2507 TCGLabel
*over
= gen_new_label();
2508 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2510 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
2511 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
2512 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
2513 static gen_helper_gvec_3_ptr
* const fns
[4] = {
2514 gen_helper_viota_m_b
, gen_helper_viota_m_h
,
2515 gen_helper_viota_m_w
, gen_helper_viota_m_d
,
2517 tcg_gen_gvec_3_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
2518 vreg_ofs(s
, a
->rs2
), cpu_env
, 0,
2519 s
->vlen
/ 8, data
, fns
[s
->sew
]);
2520 gen_set_label(over
);
2526 /* Vector Element Index Instruction */
2527 static bool trans_vid_v(DisasContext
*s
, arg_vid_v
*a
)
2529 if (vext_check_isa_ill(s
) &&
2530 vext_check_reg(s
, a
->rd
, false) &&
2531 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false)) {
2533 TCGLabel
*over
= gen_new_label();
2534 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2536 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
2537 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
2538 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
2539 static gen_helper_gvec_2_ptr
* const fns
[4] = {
2540 gen_helper_vid_v_b
, gen_helper_vid_v_h
,
2541 gen_helper_vid_v_w
, gen_helper_vid_v_d
,
2543 tcg_gen_gvec_2_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
2544 cpu_env
, 0, s
->vlen
/ 8, data
, fns
[s
->sew
]);
2545 gen_set_label(over
);
2552 *** Vector Permutation Instructions
2555 /* Integer Extract Instruction */
2557 static void load_element(TCGv_i64 dest
, TCGv_ptr base
,
2562 tcg_gen_ld8u_i64(dest
, base
, ofs
);
2565 tcg_gen_ld16u_i64(dest
, base
, ofs
);
2568 tcg_gen_ld32u_i64(dest
, base
, ofs
);
2571 tcg_gen_ld_i64(dest
, base
, ofs
);
2574 g_assert_not_reached();
2579 /* offset of the idx element with base regsiter r */
2580 static uint32_t endian_ofs(DisasContext
*s
, int r
, int idx
)
2582 #ifdef HOST_WORDS_BIGENDIAN
2583 return vreg_ofs(s
, r
) + ((idx
^ (7 >> s
->sew
)) << s
->sew
);
2585 return vreg_ofs(s
, r
) + (idx
<< s
->sew
);
2589 /* adjust the index according to the endian */
2590 static void endian_adjust(TCGv_i32 ofs
, int sew
)
2592 #ifdef HOST_WORDS_BIGENDIAN
2593 tcg_gen_xori_i32(ofs
, ofs
, 7 >> sew
);
2597 /* Load idx >= VLMAX ? 0 : vreg[idx] */
2598 static void vec_element_loadx(DisasContext
*s
, TCGv_i64 dest
,
2599 int vreg
, TCGv idx
, int vlmax
)
2601 TCGv_i32 ofs
= tcg_temp_new_i32();
2602 TCGv_ptr base
= tcg_temp_new_ptr();
2603 TCGv_i64 t_idx
= tcg_temp_new_i64();
2604 TCGv_i64 t_vlmax
, t_zero
;
2607 * Mask the index to the length so that we do
2608 * not produce an out-of-range load.
2610 tcg_gen_trunc_tl_i32(ofs
, idx
);
2611 tcg_gen_andi_i32(ofs
, ofs
, vlmax
- 1);
2613 /* Convert the index to an offset. */
2614 endian_adjust(ofs
, s
->sew
);
2615 tcg_gen_shli_i32(ofs
, ofs
, s
->sew
);
2617 /* Convert the index to a pointer. */
2618 tcg_gen_ext_i32_ptr(base
, ofs
);
2619 tcg_gen_add_ptr(base
, base
, cpu_env
);
2621 /* Perform the load. */
2622 load_element(dest
, base
,
2623 vreg_ofs(s
, vreg
), s
->sew
);
2624 tcg_temp_free_ptr(base
);
2625 tcg_temp_free_i32(ofs
);
2627 /* Flush out-of-range indexing to zero. */
2628 t_vlmax
= tcg_const_i64(vlmax
);
2629 t_zero
= tcg_const_i64(0);
2630 tcg_gen_extu_tl_i64(t_idx
, idx
);
2632 tcg_gen_movcond_i64(TCG_COND_LTU
, dest
, t_idx
,
2633 t_vlmax
, dest
, t_zero
);
2635 tcg_temp_free_i64(t_vlmax
);
2636 tcg_temp_free_i64(t_zero
);
2637 tcg_temp_free_i64(t_idx
);
2640 static void vec_element_loadi(DisasContext
*s
, TCGv_i64 dest
,
2643 load_element(dest
, cpu_env
, endian_ofs(s
, vreg
, idx
), s
->sew
);
2646 static bool trans_vext_x_v(DisasContext
*s
, arg_r
*a
)
2648 TCGv_i64 tmp
= tcg_temp_new_i64();
2649 TCGv dest
= tcg_temp_new();
2652 /* Special case vmv.x.s rd, vs2. */
2653 vec_element_loadi(s
, tmp
, a
->rs2
, 0);
2655 /* This instruction ignores LMUL and vector register groups */
2656 int vlmax
= s
->vlen
>> (3 + s
->sew
);
2657 vec_element_loadx(s
, tmp
, a
->rs2
, cpu_gpr
[a
->rs1
], vlmax
);
2659 tcg_gen_trunc_i64_tl(dest
, tmp
);
2660 gen_set_gpr(a
->rd
, dest
);
2662 tcg_temp_free(dest
);
2663 tcg_temp_free_i64(tmp
);
2667 /* Integer Scalar Move Instruction */
2669 static void store_element(TCGv_i64 val
, TCGv_ptr base
,
2674 tcg_gen_st8_i64(val
, base
, ofs
);
2677 tcg_gen_st16_i64(val
, base
, ofs
);
2680 tcg_gen_st32_i64(val
, base
, ofs
);
2683 tcg_gen_st_i64(val
, base
, ofs
);
2686 g_assert_not_reached();
2692 * Store vreg[idx] = val.
2693 * The index must be in range of VLMAX.
2695 static void vec_element_storei(DisasContext
*s
, int vreg
,
2696 int idx
, TCGv_i64 val
)
2698 store_element(val
, cpu_env
, endian_ofs(s
, vreg
, idx
), s
->sew
);
2701 /* vmv.s.x vd, rs1 # vd[0] = rs1 */
2702 static bool trans_vmv_s_x(DisasContext
*s
, arg_vmv_s_x
*a
)
2704 if (vext_check_isa_ill(s
)) {
2705 /* This instruction ignores LMUL and vector register groups */
2706 int maxsz
= s
->vlen
>> 3;
2708 TCGLabel
*over
= gen_new_label();
2710 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2711 tcg_gen_gvec_dup_imm(SEW64
, vreg_ofs(s
, a
->rd
), maxsz
, maxsz
, 0);
2716 t1
= tcg_temp_new_i64();
2717 tcg_gen_extu_tl_i64(t1
, cpu_gpr
[a
->rs1
]);
2718 vec_element_storei(s
, a
->rd
, 0, t1
);
2719 tcg_temp_free_i64(t1
);
2721 gen_set_label(over
);
2727 /* Floating-Point Scalar Move Instructions */
2728 static bool trans_vfmv_f_s(DisasContext
*s
, arg_vfmv_f_s
*a
)
2730 if (!s
->vill
&& has_ext(s
, RVF
) &&
2731 (s
->mstatus_fs
!= 0) && (s
->sew
!= 0)) {
2732 unsigned int len
= 8 << s
->sew
;
2734 vec_element_loadi(s
, cpu_fpr
[a
->rd
], a
->rs2
, 0);
2736 tcg_gen_ori_i64(cpu_fpr
[a
->rd
], cpu_fpr
[a
->rd
],
2737 MAKE_64BIT_MASK(len
, 64 - len
));
2746 /* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */
2747 static bool trans_vfmv_s_f(DisasContext
*s
, arg_vfmv_s_f
*a
)
2749 if (!s
->vill
&& has_ext(s
, RVF
) && (s
->sew
!= 0)) {
2751 /* The instructions ignore LMUL and vector register group. */
2752 uint32_t vlmax
= s
->vlen
>> 3;
2754 /* if vl == 0, skip vector register write back */
2755 TCGLabel
*over
= gen_new_label();
2756 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2758 /* zeroed all elements */
2759 tcg_gen_gvec_dup_imm(SEW64
, vreg_ofs(s
, a
->rd
), vlmax
, vlmax
, 0);
2761 /* NaN-box f[rs1] as necessary for SEW */
2762 t1
= tcg_temp_new_i64();
2763 if (s
->sew
== MO_64
&& !has_ext(s
, RVD
)) {
2764 tcg_gen_ori_i64(t1
, cpu_fpr
[a
->rs1
], MAKE_64BIT_MASK(32, 32));
2766 tcg_gen_mov_i64(t1
, cpu_fpr
[a
->rs1
]);
2768 vec_element_storei(s
, a
->rd
, 0, t1
);
2769 tcg_temp_free_i64(t1
);
2770 gen_set_label(over
);
2776 /* Vector Slide Instructions */
2777 static bool slideup_check(DisasContext
*s
, arg_rmrr
*a
)
2779 return (vext_check_isa_ill(s
) &&
2780 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2781 vext_check_reg(s
, a
->rd
, false) &&
2782 vext_check_reg(s
, a
->rs2
, false) &&
2786 GEN_OPIVX_TRANS(vslideup_vx
, slideup_check
)
2787 GEN_OPIVX_TRANS(vslide1up_vx
, slideup_check
)
2788 GEN_OPIVI_TRANS(vslideup_vi
, 1, vslideup_vx
, slideup_check
)
2790 GEN_OPIVX_TRANS(vslidedown_vx
, opivx_check
)
2791 GEN_OPIVX_TRANS(vslide1down_vx
, opivx_check
)
2792 GEN_OPIVI_TRANS(vslidedown_vi
, 1, vslidedown_vx
, opivx_check
)
2794 /* Vector Register Gather Instruction */
2795 static bool vrgather_vv_check(DisasContext
*s
, arg_rmrr
*a
)
2797 return (vext_check_isa_ill(s
) &&
2798 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2799 vext_check_reg(s
, a
->rd
, false) &&
2800 vext_check_reg(s
, a
->rs1
, false) &&
2801 vext_check_reg(s
, a
->rs2
, false) &&
2802 (a
->rd
!= a
->rs2
) && (a
->rd
!= a
->rs1
));
2805 GEN_OPIVV_TRANS(vrgather_vv
, vrgather_vv_check
)
2807 static bool vrgather_vx_check(DisasContext
*s
, arg_rmrr
*a
)
2809 return (vext_check_isa_ill(s
) &&
2810 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2811 vext_check_reg(s
, a
->rd
, false) &&
2812 vext_check_reg(s
, a
->rs2
, false) &&
2816 /* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */
2817 static bool trans_vrgather_vx(DisasContext
*s
, arg_rmrr
*a
)
2819 if (!vrgather_vx_check(s
, a
)) {
2823 if (a
->vm
&& s
->vl_eq_vlmax
) {
2824 int vlmax
= s
->vlen
/ s
->mlen
;
2825 TCGv_i64 dest
= tcg_temp_new_i64();
2828 vec_element_loadi(s
, dest
, a
->rs2
, 0);
2830 vec_element_loadx(s
, dest
, a
->rs2
, cpu_gpr
[a
->rs1
], vlmax
);
2833 tcg_gen_gvec_dup_i64(s
->sew
, vreg_ofs(s
, a
->rd
),
2834 MAXSZ(s
), MAXSZ(s
), dest
);
2835 tcg_temp_free_i64(dest
);
2837 static gen_helper_opivx
* const fns
[4] = {
2838 gen_helper_vrgather_vx_b
, gen_helper_vrgather_vx_h
,
2839 gen_helper_vrgather_vx_w
, gen_helper_vrgather_vx_d
2841 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fns
[s
->sew
], s
);
2846 /* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */
2847 static bool trans_vrgather_vi(DisasContext
*s
, arg_rmrr
*a
)
2849 if (!vrgather_vx_check(s
, a
)) {
2853 if (a
->vm
&& s
->vl_eq_vlmax
) {
2854 if (a
->rs1
>= s
->vlen
/ s
->mlen
) {
2855 tcg_gen_gvec_dup_imm(SEW64
, vreg_ofs(s
, a
->rd
),
2856 MAXSZ(s
), MAXSZ(s
), 0);
2858 tcg_gen_gvec_dup_mem(s
->sew
, vreg_ofs(s
, a
->rd
),
2859 endian_ofs(s
, a
->rs2
, a
->rs1
),
2860 MAXSZ(s
), MAXSZ(s
));
2863 static gen_helper_opivx
* const fns
[4] = {
2864 gen_helper_vrgather_vx_b
, gen_helper_vrgather_vx_h
,
2865 gen_helper_vrgather_vx_w
, gen_helper_vrgather_vx_d
2867 return opivi_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fns
[s
->sew
], s
, 1);
2872 /* Vector Compress Instruction */
2873 static bool vcompress_vm_check(DisasContext
*s
, arg_r
*a
)
2875 return (vext_check_isa_ill(s
) &&
2876 vext_check_reg(s
, a
->rd
, false) &&
2877 vext_check_reg(s
, a
->rs2
, false) &&
2878 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs1
, 1) &&
2882 static bool trans_vcompress_vm(DisasContext
*s
, arg_r
*a
)
2884 if (vcompress_vm_check(s
, a
)) {
2886 static gen_helper_gvec_4_ptr
* const fns
[4] = {
2887 gen_helper_vcompress_vm_b
, gen_helper_vcompress_vm_h
,
2888 gen_helper_vcompress_vm_w
, gen_helper_vcompress_vm_d
,
2890 TCGLabel
*over
= gen_new_label();
2891 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2893 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
2894 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
2895 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
2896 vreg_ofs(s
, a
->rs1
), vreg_ofs(s
, a
->rs2
),
2897 cpu_env
, 0, s
->vlen
/ 8, data
, fns
[s
->sew
]);
2898 gen_set_label(over
);