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
);
516 static bool ld_index_check(DisasContext
*s
, arg_rnfvm
* a
)
518 return (vext_check_isa_ill(s
) &&
519 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
520 vext_check_reg(s
, a
->rd
, false) &&
521 vext_check_reg(s
, a
->rs2
, false) &&
522 vext_check_nf(s
, a
->nf
));
525 GEN_VEXT_TRANS(vlxb_v
, 0, rnfvm
, ld_index_op
, ld_index_check
)
526 GEN_VEXT_TRANS(vlxh_v
, 1, rnfvm
, ld_index_op
, ld_index_check
)
527 GEN_VEXT_TRANS(vlxw_v
, 2, rnfvm
, ld_index_op
, ld_index_check
)
528 GEN_VEXT_TRANS(vlxe_v
, 3, rnfvm
, ld_index_op
, ld_index_check
)
529 GEN_VEXT_TRANS(vlxbu_v
, 4, rnfvm
, ld_index_op
, ld_index_check
)
530 GEN_VEXT_TRANS(vlxhu_v
, 5, rnfvm
, ld_index_op
, ld_index_check
)
531 GEN_VEXT_TRANS(vlxwu_v
, 6, rnfvm
, ld_index_op
, ld_index_check
)
533 static bool st_index_op(DisasContext
*s
, arg_rnfvm
*a
, uint8_t seq
)
536 gen_helper_ldst_index
*fn
;
537 static gen_helper_ldst_index
* const fns
[4][4] = {
538 { gen_helper_vsxb_v_b
, gen_helper_vsxb_v_h
,
539 gen_helper_vsxb_v_w
, gen_helper_vsxb_v_d
},
540 { NULL
, gen_helper_vsxh_v_h
,
541 gen_helper_vsxh_v_w
, gen_helper_vsxh_v_d
},
543 gen_helper_vsxw_v_w
, gen_helper_vsxw_v_d
},
544 { gen_helper_vsxe_v_b
, gen_helper_vsxe_v_h
,
545 gen_helper_vsxe_v_w
, gen_helper_vsxe_v_d
}
548 fn
= fns
[seq
][s
->sew
];
553 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
554 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
555 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
556 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
557 return ldst_index_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
560 static bool st_index_check(DisasContext
*s
, arg_rnfvm
* a
)
562 return (vext_check_isa_ill(s
) &&
563 vext_check_reg(s
, a
->rd
, false) &&
564 vext_check_reg(s
, a
->rs2
, false) &&
565 vext_check_nf(s
, a
->nf
));
568 GEN_VEXT_TRANS(vsxb_v
, 0, rnfvm
, st_index_op
, st_index_check
)
569 GEN_VEXT_TRANS(vsxh_v
, 1, rnfvm
, st_index_op
, st_index_check
)
570 GEN_VEXT_TRANS(vsxw_v
, 2, rnfvm
, st_index_op
, st_index_check
)
571 GEN_VEXT_TRANS(vsxe_v
, 3, rnfvm
, st_index_op
, st_index_check
)
574 *** unit stride fault-only-first load
576 static bool ldff_trans(uint32_t vd
, uint32_t rs1
, uint32_t data
,
577 gen_helper_ldst_us
*fn
, DisasContext
*s
)
583 TCGLabel
*over
= gen_new_label();
584 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
586 dest
= tcg_temp_new_ptr();
587 mask
= tcg_temp_new_ptr();
588 base
= tcg_temp_new();
589 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
591 gen_get_gpr(base
, rs1
);
592 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
593 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
595 fn(dest
, mask
, base
, cpu_env
, desc
);
597 tcg_temp_free_ptr(dest
);
598 tcg_temp_free_ptr(mask
);
600 tcg_temp_free_i32(desc
);
605 static bool ldff_op(DisasContext
*s
, arg_r2nfvm
*a
, uint8_t seq
)
608 gen_helper_ldst_us
*fn
;
609 static gen_helper_ldst_us
* const fns
[7][4] = {
610 { gen_helper_vlbff_v_b
, gen_helper_vlbff_v_h
,
611 gen_helper_vlbff_v_w
, gen_helper_vlbff_v_d
},
612 { NULL
, gen_helper_vlhff_v_h
,
613 gen_helper_vlhff_v_w
, gen_helper_vlhff_v_d
},
615 gen_helper_vlwff_v_w
, gen_helper_vlwff_v_d
},
616 { gen_helper_vleff_v_b
, gen_helper_vleff_v_h
,
617 gen_helper_vleff_v_w
, gen_helper_vleff_v_d
},
618 { gen_helper_vlbuff_v_b
, gen_helper_vlbuff_v_h
,
619 gen_helper_vlbuff_v_w
, gen_helper_vlbuff_v_d
},
620 { NULL
, gen_helper_vlhuff_v_h
,
621 gen_helper_vlhuff_v_w
, gen_helper_vlhuff_v_d
},
623 gen_helper_vlwuff_v_w
, gen_helper_vlwuff_v_d
}
626 fn
= fns
[seq
][s
->sew
];
631 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
632 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
633 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
634 data
= FIELD_DP32(data
, VDATA
, NF
, a
->nf
);
635 return ldff_trans(a
->rd
, a
->rs1
, data
, fn
, s
);
638 GEN_VEXT_TRANS(vlbff_v
, 0, r2nfvm
, ldff_op
, ld_us_check
)
639 GEN_VEXT_TRANS(vlhff_v
, 1, r2nfvm
, ldff_op
, ld_us_check
)
640 GEN_VEXT_TRANS(vlwff_v
, 2, r2nfvm
, ldff_op
, ld_us_check
)
641 GEN_VEXT_TRANS(vleff_v
, 3, r2nfvm
, ldff_op
, ld_us_check
)
642 GEN_VEXT_TRANS(vlbuff_v
, 4, r2nfvm
, ldff_op
, ld_us_check
)
643 GEN_VEXT_TRANS(vlhuff_v
, 5, r2nfvm
, ldff_op
, ld_us_check
)
644 GEN_VEXT_TRANS(vlwuff_v
, 6, r2nfvm
, ldff_op
, ld_us_check
)
647 *** vector atomic operation
649 typedef void gen_helper_amo(TCGv_ptr
, TCGv_ptr
, TCGv
, TCGv_ptr
,
652 static bool amo_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
,
653 uint32_t data
, gen_helper_amo
*fn
, DisasContext
*s
)
655 TCGv_ptr dest
, mask
, index
;
659 TCGLabel
*over
= gen_new_label();
660 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
662 dest
= tcg_temp_new_ptr();
663 mask
= tcg_temp_new_ptr();
664 index
= tcg_temp_new_ptr();
665 base
= tcg_temp_new();
666 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
668 gen_get_gpr(base
, rs1
);
669 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
670 tcg_gen_addi_ptr(index
, cpu_env
, vreg_ofs(s
, vs2
));
671 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
673 fn(dest
, mask
, base
, index
, cpu_env
, desc
);
675 tcg_temp_free_ptr(dest
);
676 tcg_temp_free_ptr(mask
);
677 tcg_temp_free_ptr(index
);
679 tcg_temp_free_i32(desc
);
684 static bool amo_op(DisasContext
*s
, arg_rwdvm
*a
, uint8_t seq
)
688 static gen_helper_amo
*const fnsw
[9] = {
689 /* no atomic operation */
690 gen_helper_vamoswapw_v_w
,
691 gen_helper_vamoaddw_v_w
,
692 gen_helper_vamoxorw_v_w
,
693 gen_helper_vamoandw_v_w
,
694 gen_helper_vamoorw_v_w
,
695 gen_helper_vamominw_v_w
,
696 gen_helper_vamomaxw_v_w
,
697 gen_helper_vamominuw_v_w
,
698 gen_helper_vamomaxuw_v_w
700 #ifdef TARGET_RISCV64
701 static gen_helper_amo
*const fnsd
[18] = {
702 gen_helper_vamoswapw_v_d
,
703 gen_helper_vamoaddw_v_d
,
704 gen_helper_vamoxorw_v_d
,
705 gen_helper_vamoandw_v_d
,
706 gen_helper_vamoorw_v_d
,
707 gen_helper_vamominw_v_d
,
708 gen_helper_vamomaxw_v_d
,
709 gen_helper_vamominuw_v_d
,
710 gen_helper_vamomaxuw_v_d
,
711 gen_helper_vamoswapd_v_d
,
712 gen_helper_vamoaddd_v_d
,
713 gen_helper_vamoxord_v_d
,
714 gen_helper_vamoandd_v_d
,
715 gen_helper_vamoord_v_d
,
716 gen_helper_vamomind_v_d
,
717 gen_helper_vamomaxd_v_d
,
718 gen_helper_vamominud_v_d
,
719 gen_helper_vamomaxud_v_d
723 if (tb_cflags(s
->base
.tb
) & CF_PARALLEL
) {
724 gen_helper_exit_atomic(cpu_env
);
725 s
->base
.is_jmp
= DISAS_NORETURN
;
729 #ifdef TARGET_RISCV64
732 /* Check done in amo_check(). */
733 g_assert_not_reached();
740 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
741 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
742 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
743 data
= FIELD_DP32(data
, VDATA
, WD
, a
->wd
);
744 return amo_trans(a
->rd
, a
->rs1
, a
->rs2
, data
, fn
, s
);
747 * There are two rules check here.
749 * 1. SEW must be at least as wide as the AMO memory element size.
751 * 2. If SEW is greater than XLEN, an illegal instruction exception is raised.
753 static bool amo_check(DisasContext
*s
, arg_rwdvm
* a
)
755 return (!s
->vill
&& has_ext(s
, RVA
) &&
756 (!a
->wd
|| vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false)) &&
757 vext_check_reg(s
, a
->rd
, false) &&
758 vext_check_reg(s
, a
->rs2
, false) &&
759 ((1 << s
->sew
) <= sizeof(target_ulong
)) &&
760 ((1 << s
->sew
) >= 4));
763 GEN_VEXT_TRANS(vamoswapw_v
, 0, rwdvm
, amo_op
, amo_check
)
764 GEN_VEXT_TRANS(vamoaddw_v
, 1, rwdvm
, amo_op
, amo_check
)
765 GEN_VEXT_TRANS(vamoxorw_v
, 2, rwdvm
, amo_op
, amo_check
)
766 GEN_VEXT_TRANS(vamoandw_v
, 3, rwdvm
, amo_op
, amo_check
)
767 GEN_VEXT_TRANS(vamoorw_v
, 4, rwdvm
, amo_op
, amo_check
)
768 GEN_VEXT_TRANS(vamominw_v
, 5, rwdvm
, amo_op
, amo_check
)
769 GEN_VEXT_TRANS(vamomaxw_v
, 6, rwdvm
, amo_op
, amo_check
)
770 GEN_VEXT_TRANS(vamominuw_v
, 7, rwdvm
, amo_op
, amo_check
)
771 GEN_VEXT_TRANS(vamomaxuw_v
, 8, rwdvm
, amo_op
, amo_check
)
772 #ifdef TARGET_RISCV64
773 GEN_VEXT_TRANS(vamoswapd_v
, 9, rwdvm
, amo_op
, amo_check
)
774 GEN_VEXT_TRANS(vamoaddd_v
, 10, rwdvm
, amo_op
, amo_check
)
775 GEN_VEXT_TRANS(vamoxord_v
, 11, rwdvm
, amo_op
, amo_check
)
776 GEN_VEXT_TRANS(vamoandd_v
, 12, rwdvm
, amo_op
, amo_check
)
777 GEN_VEXT_TRANS(vamoord_v
, 13, rwdvm
, amo_op
, amo_check
)
778 GEN_VEXT_TRANS(vamomind_v
, 14, rwdvm
, amo_op
, amo_check
)
779 GEN_VEXT_TRANS(vamomaxd_v
, 15, rwdvm
, amo_op
, amo_check
)
780 GEN_VEXT_TRANS(vamominud_v
, 16, rwdvm
, amo_op
, amo_check
)
781 GEN_VEXT_TRANS(vamomaxud_v
, 17, rwdvm
, amo_op
, amo_check
)
785 *** Vector Integer Arithmetic Instructions
787 #define MAXSZ(s) (s->vlen >> (3 - s->lmul))
789 static bool opivv_check(DisasContext
*s
, arg_rmrr
*a
)
791 return (vext_check_isa_ill(s
) &&
792 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
793 vext_check_reg(s
, a
->rd
, false) &&
794 vext_check_reg(s
, a
->rs2
, false) &&
795 vext_check_reg(s
, a
->rs1
, false));
798 typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t,
799 uint32_t, uint32_t, uint32_t);
802 do_opivv_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen3Fn
*gvec_fn
,
803 gen_helper_gvec_4_ptr
*fn
)
805 TCGLabel
*over
= gen_new_label();
806 if (!opivv_check(s
, a
)) {
810 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
812 if (a
->vm
&& s
->vl_eq_vlmax
) {
813 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
),
814 vreg_ofs(s
, a
->rs2
), vreg_ofs(s
, a
->rs1
),
819 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
820 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
821 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
822 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
823 vreg_ofs(s
, a
->rs1
), vreg_ofs(s
, a
->rs2
),
824 cpu_env
, 0, s
->vlen
/ 8, data
, fn
);
830 /* OPIVV with GVEC IR */
831 #define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \
832 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
834 static gen_helper_gvec_4_ptr * const fns[4] = { \
835 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
836 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
838 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
841 GEN_OPIVV_GVEC_TRANS(vadd_vv
, add
)
842 GEN_OPIVV_GVEC_TRANS(vsub_vv
, sub
)
844 typedef void gen_helper_opivx(TCGv_ptr
, TCGv_ptr
, TCGv
, TCGv_ptr
,
847 static bool opivx_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
, uint32_t vm
,
848 gen_helper_opivx
*fn
, DisasContext
*s
)
850 TCGv_ptr dest
, src2
, mask
;
855 TCGLabel
*over
= gen_new_label();
856 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
858 dest
= tcg_temp_new_ptr();
859 mask
= tcg_temp_new_ptr();
860 src2
= tcg_temp_new_ptr();
861 src1
= tcg_temp_new();
862 gen_get_gpr(src1
, rs1
);
864 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
865 data
= FIELD_DP32(data
, VDATA
, VM
, vm
);
866 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
867 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
869 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
870 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
871 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
873 fn(dest
, mask
, src1
, src2
, cpu_env
, desc
);
875 tcg_temp_free_ptr(dest
);
876 tcg_temp_free_ptr(mask
);
877 tcg_temp_free_ptr(src2
);
879 tcg_temp_free_i32(desc
);
884 static bool opivx_check(DisasContext
*s
, arg_rmrr
*a
)
886 return (vext_check_isa_ill(s
) &&
887 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
888 vext_check_reg(s
, a
->rd
, false) &&
889 vext_check_reg(s
, a
->rs2
, false));
892 typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64
,
896 do_opivx_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen2sFn
*gvec_fn
,
897 gen_helper_opivx
*fn
)
899 if (!opivx_check(s
, a
)) {
903 if (a
->vm
&& s
->vl_eq_vlmax
) {
904 TCGv_i64 src1
= tcg_temp_new_i64();
905 TCGv tmp
= tcg_temp_new();
907 gen_get_gpr(tmp
, a
->rs1
);
908 tcg_gen_ext_tl_i64(src1
, tmp
);
909 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
910 src1
, MAXSZ(s
), MAXSZ(s
));
912 tcg_temp_free_i64(src1
);
916 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
919 /* OPIVX with GVEC IR */
920 #define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \
921 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
923 static gen_helper_opivx * const fns[4] = { \
924 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
925 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
927 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
930 GEN_OPIVX_GVEC_TRANS(vadd_vx
, adds
)
931 GEN_OPIVX_GVEC_TRANS(vsub_vx
, subs
)
933 static void gen_vec_rsub8_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
935 tcg_gen_vec_sub8_i64(d
, b
, a
);
938 static void gen_vec_rsub16_i64(TCGv_i64 d
, TCGv_i64 a
, TCGv_i64 b
)
940 tcg_gen_vec_sub8_i64(d
, b
, a
);
943 static void gen_rsub_i32(TCGv_i32 ret
, TCGv_i32 arg1
, TCGv_i32 arg2
)
945 tcg_gen_sub_i32(ret
, arg2
, arg1
);
948 static void gen_rsub_i64(TCGv_i64 ret
, TCGv_i64 arg1
, TCGv_i64 arg2
)
950 tcg_gen_sub_i64(ret
, arg2
, arg1
);
953 static void gen_rsub_vec(unsigned vece
, TCGv_vec r
, TCGv_vec a
, TCGv_vec b
)
955 tcg_gen_sub_vec(vece
, r
, b
, a
);
958 static void tcg_gen_gvec_rsubs(unsigned vece
, uint32_t dofs
, uint32_t aofs
,
959 TCGv_i64 c
, uint32_t oprsz
, uint32_t maxsz
)
961 static const GVecGen2s rsub_op
[4] = {
962 { .fni8
= gen_vec_rsub8_i64
,
963 .fniv
= gen_rsub_vec
,
964 .fno
= gen_helper_vec_rsubs8
,
966 { .fni8
= gen_vec_rsub16_i64
,
967 .fniv
= gen_rsub_vec
,
968 .fno
= gen_helper_vec_rsubs16
,
970 { .fni4
= gen_rsub_i32
,
971 .fniv
= gen_rsub_vec
,
972 .fno
= gen_helper_vec_rsubs32
,
974 { .fni8
= gen_rsub_i64
,
975 .fniv
= gen_rsub_vec
,
976 .fno
= gen_helper_vec_rsubs64
,
977 .prefer_i64
= TCG_TARGET_REG_BITS
== 64,
981 tcg_debug_assert(vece
<= MO_64
);
982 tcg_gen_gvec_2s(dofs
, aofs
, oprsz
, maxsz
, c
, &rsub_op
[vece
]);
985 GEN_OPIVX_GVEC_TRANS(vrsub_vx
, rsubs
)
987 static bool opivi_trans(uint32_t vd
, uint32_t imm
, uint32_t vs2
, uint32_t vm
,
988 gen_helper_opivx
*fn
, DisasContext
*s
, int zx
)
990 TCGv_ptr dest
, src2
, mask
;
995 TCGLabel
*over
= gen_new_label();
996 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
998 dest
= tcg_temp_new_ptr();
999 mask
= tcg_temp_new_ptr();
1000 src2
= tcg_temp_new_ptr();
1002 src1
= tcg_const_tl(imm
);
1004 src1
= tcg_const_tl(sextract64(imm
, 0, 5));
1006 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1007 data
= FIELD_DP32(data
, VDATA
, VM
, vm
);
1008 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1009 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1011 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
1012 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
1013 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
1015 fn(dest
, mask
, src1
, src2
, cpu_env
, desc
);
1017 tcg_temp_free_ptr(dest
);
1018 tcg_temp_free_ptr(mask
);
1019 tcg_temp_free_ptr(src2
);
1020 tcg_temp_free(src1
);
1021 tcg_temp_free_i32(desc
);
1022 gen_set_label(over
);
1026 typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t,
1027 uint32_t, uint32_t);
1030 do_opivi_gvec(DisasContext
*s
, arg_rmrr
*a
, GVecGen2iFn
*gvec_fn
,
1031 gen_helper_opivx
*fn
, int zx
)
1033 if (!opivx_check(s
, a
)) {
1037 if (a
->vm
&& s
->vl_eq_vlmax
) {
1039 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1040 extract64(a
->rs1
, 0, 5), MAXSZ(s
), MAXSZ(s
));
1042 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1043 sextract64(a
->rs1
, 0, 5), MAXSZ(s
), MAXSZ(s
));
1046 return opivi_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
, zx
);
1051 /* OPIVI with GVEC IR */
1052 #define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \
1053 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1055 static gen_helper_opivx * const fns[4] = { \
1056 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
1057 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
1059 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \
1063 GEN_OPIVI_GVEC_TRANS(vadd_vi
, 0, vadd_vx
, addi
)
1065 static void tcg_gen_gvec_rsubi(unsigned vece
, uint32_t dofs
, uint32_t aofs
,
1066 int64_t c
, uint32_t oprsz
, uint32_t maxsz
)
1068 TCGv_i64 tmp
= tcg_const_i64(c
);
1069 tcg_gen_gvec_rsubs(vece
, dofs
, aofs
, tmp
, oprsz
, maxsz
);
1070 tcg_temp_free_i64(tmp
);
1073 GEN_OPIVI_GVEC_TRANS(vrsub_vi
, 0, vrsub_vx
, rsubi
)
1075 /* Vector Widening Integer Add/Subtract */
1077 /* OPIVV with WIDEN */
1078 static bool opivv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1080 return (vext_check_isa_ill(s
) &&
1081 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1082 vext_check_reg(s
, a
->rd
, true) &&
1083 vext_check_reg(s
, a
->rs2
, false) &&
1084 vext_check_reg(s
, a
->rs1
, false) &&
1085 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1087 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1089 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1092 static bool do_opivv_widen(DisasContext
*s
, arg_rmrr
*a
,
1093 gen_helper_gvec_4_ptr
*fn
,
1094 bool (*checkfn
)(DisasContext
*, arg_rmrr
*))
1096 if (checkfn(s
, a
)) {
1098 TCGLabel
*over
= gen_new_label();
1099 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1101 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1102 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
1103 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1104 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
1105 vreg_ofs(s
, a
->rs1
),
1106 vreg_ofs(s
, a
->rs2
),
1107 cpu_env
, 0, s
->vlen
/ 8,
1109 gen_set_label(over
);
1115 #define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \
1116 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1118 static gen_helper_gvec_4_ptr * const fns[3] = { \
1119 gen_helper_##NAME##_b, \
1120 gen_helper_##NAME##_h, \
1121 gen_helper_##NAME##_w \
1123 return do_opivv_widen(s, a, fns[s->sew], CHECK); \
1126 GEN_OPIVV_WIDEN_TRANS(vwaddu_vv
, opivv_widen_check
)
1127 GEN_OPIVV_WIDEN_TRANS(vwadd_vv
, opivv_widen_check
)
1128 GEN_OPIVV_WIDEN_TRANS(vwsubu_vv
, opivv_widen_check
)
1129 GEN_OPIVV_WIDEN_TRANS(vwsub_vv
, opivv_widen_check
)
1131 /* OPIVX with WIDEN */
1132 static bool opivx_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1134 return (vext_check_isa_ill(s
) &&
1135 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1136 vext_check_reg(s
, a
->rd
, true) &&
1137 vext_check_reg(s
, a
->rs2
, false) &&
1138 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1140 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1143 static bool do_opivx_widen(DisasContext
*s
, arg_rmrr
*a
,
1144 gen_helper_opivx
*fn
)
1146 if (opivx_widen_check(s
, a
)) {
1147 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1152 #define GEN_OPIVX_WIDEN_TRANS(NAME) \
1153 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1155 static gen_helper_opivx * const fns[3] = { \
1156 gen_helper_##NAME##_b, \
1157 gen_helper_##NAME##_h, \
1158 gen_helper_##NAME##_w \
1160 return do_opivx_widen(s, a, fns[s->sew]); \
1163 GEN_OPIVX_WIDEN_TRANS(vwaddu_vx
)
1164 GEN_OPIVX_WIDEN_TRANS(vwadd_vx
)
1165 GEN_OPIVX_WIDEN_TRANS(vwsubu_vx
)
1166 GEN_OPIVX_WIDEN_TRANS(vwsub_vx
)
1168 /* WIDEN OPIVV with WIDEN */
1169 static bool opiwv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1171 return (vext_check_isa_ill(s
) &&
1172 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1173 vext_check_reg(s
, a
->rd
, true) &&
1174 vext_check_reg(s
, a
->rs2
, true) &&
1175 vext_check_reg(s
, a
->rs1
, false) &&
1176 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1178 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1181 static bool do_opiwv_widen(DisasContext
*s
, arg_rmrr
*a
,
1182 gen_helper_gvec_4_ptr
*fn
)
1184 if (opiwv_widen_check(s
, a
)) {
1186 TCGLabel
*over
= gen_new_label();
1187 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1189 data
= FIELD_DP32(data
, VDATA
, MLEN
, s
->mlen
);
1190 data
= FIELD_DP32(data
, VDATA
, VM
, a
->vm
);
1191 data
= FIELD_DP32(data
, VDATA
, LMUL
, s
->lmul
);
1192 tcg_gen_gvec_4_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, 0),
1193 vreg_ofs(s
, a
->rs1
),
1194 vreg_ofs(s
, a
->rs2
),
1195 cpu_env
, 0, s
->vlen
/ 8, data
, fn
);
1196 gen_set_label(over
);
1202 #define GEN_OPIWV_WIDEN_TRANS(NAME) \
1203 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1205 static gen_helper_gvec_4_ptr * const fns[3] = { \
1206 gen_helper_##NAME##_b, \
1207 gen_helper_##NAME##_h, \
1208 gen_helper_##NAME##_w \
1210 return do_opiwv_widen(s, a, fns[s->sew]); \
1213 GEN_OPIWV_WIDEN_TRANS(vwaddu_wv
)
1214 GEN_OPIWV_WIDEN_TRANS(vwadd_wv
)
1215 GEN_OPIWV_WIDEN_TRANS(vwsubu_wv
)
1216 GEN_OPIWV_WIDEN_TRANS(vwsub_wv
)
1218 /* WIDEN OPIVX with WIDEN */
1219 static bool opiwx_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1221 return (vext_check_isa_ill(s
) &&
1222 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1223 vext_check_reg(s
, a
->rd
, true) &&
1224 vext_check_reg(s
, a
->rs2
, true) &&
1225 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1228 static bool do_opiwx_widen(DisasContext
*s
, arg_rmrr
*a
,
1229 gen_helper_opivx
*fn
)
1231 if (opiwx_widen_check(s
, a
)) {
1232 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1237 #define GEN_OPIWX_WIDEN_TRANS(NAME) \
1238 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1240 static gen_helper_opivx * const fns[3] = { \
1241 gen_helper_##NAME##_b, \
1242 gen_helper_##NAME##_h, \
1243 gen_helper_##NAME##_w \
1245 return do_opiwx_widen(s, a, fns[s->sew]); \
1248 GEN_OPIWX_WIDEN_TRANS(vwaddu_wx
)
1249 GEN_OPIWX_WIDEN_TRANS(vwadd_wx
)
1250 GEN_OPIWX_WIDEN_TRANS(vwsubu_wx
)
1251 GEN_OPIWX_WIDEN_TRANS(vwsub_wx
)
1253 /* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
1254 /* OPIVV without GVEC IR */
1255 #define GEN_OPIVV_TRANS(NAME, CHECK) \
1256 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1258 if (CHECK(s, a)) { \
1259 uint32_t data = 0; \
1260 static gen_helper_gvec_4_ptr * const fns[4] = { \
1261 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1262 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1264 TCGLabel *over = gen_new_label(); \
1265 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1267 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1268 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1269 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1270 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1271 vreg_ofs(s, a->rs1), \
1272 vreg_ofs(s, a->rs2), cpu_env, 0, \
1273 s->vlen / 8, data, fns[s->sew]); \
1274 gen_set_label(over); \
1281 * For vadc and vsbc, an illegal instruction exception is raised if the
1282 * destination vector register is v0 and LMUL > 1. (Section 12.3)
1284 static bool opivv_vadc_check(DisasContext
*s
, arg_rmrr
*a
)
1286 return (vext_check_isa_ill(s
) &&
1287 vext_check_reg(s
, a
->rd
, false) &&
1288 vext_check_reg(s
, a
->rs2
, false) &&
1289 vext_check_reg(s
, a
->rs1
, false) &&
1290 ((a
->rd
!= 0) || (s
->lmul
== 0)));
1293 GEN_OPIVV_TRANS(vadc_vvm
, opivv_vadc_check
)
1294 GEN_OPIVV_TRANS(vsbc_vvm
, opivv_vadc_check
)
1297 * For vmadc and vmsbc, an illegal instruction exception is raised if the
1298 * destination vector register overlaps a source vector register group.
1300 static bool opivv_vmadc_check(DisasContext
*s
, arg_rmrr
*a
)
1302 return (vext_check_isa_ill(s
) &&
1303 vext_check_reg(s
, a
->rs2
, false) &&
1304 vext_check_reg(s
, a
->rs1
, false) &&
1305 vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
1306 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
));
1309 GEN_OPIVV_TRANS(vmadc_vvm
, opivv_vmadc_check
)
1310 GEN_OPIVV_TRANS(vmsbc_vvm
, opivv_vmadc_check
)
1312 static bool opivx_vadc_check(DisasContext
*s
, arg_rmrr
*a
)
1314 return (vext_check_isa_ill(s
) &&
1315 vext_check_reg(s
, a
->rd
, false) &&
1316 vext_check_reg(s
, a
->rs2
, false) &&
1317 ((a
->rd
!= 0) || (s
->lmul
== 0)));
1320 /* OPIVX without GVEC IR */
1321 #define GEN_OPIVX_TRANS(NAME, CHECK) \
1322 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1324 if (CHECK(s, a)) { \
1325 static gen_helper_opivx * const fns[4] = { \
1326 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1327 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1330 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1335 GEN_OPIVX_TRANS(vadc_vxm
, opivx_vadc_check
)
1336 GEN_OPIVX_TRANS(vsbc_vxm
, opivx_vadc_check
)
1338 static bool opivx_vmadc_check(DisasContext
*s
, arg_rmrr
*a
)
1340 return (vext_check_isa_ill(s
) &&
1341 vext_check_reg(s
, a
->rs2
, false) &&
1342 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
));
1345 GEN_OPIVX_TRANS(vmadc_vxm
, opivx_vmadc_check
)
1346 GEN_OPIVX_TRANS(vmsbc_vxm
, opivx_vmadc_check
)
1348 /* OPIVI without GVEC IR */
1349 #define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \
1350 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1352 if (CHECK(s, a)) { \
1353 static gen_helper_opivx * const fns[4] = { \
1354 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
1355 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
1357 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
1358 fns[s->sew], s, ZX); \
1363 GEN_OPIVI_TRANS(vadc_vim
, 0, vadc_vxm
, opivx_vadc_check
)
1364 GEN_OPIVI_TRANS(vmadc_vim
, 0, vmadc_vxm
, opivx_vmadc_check
)
1366 /* Vector Bitwise Logical Instructions */
1367 GEN_OPIVV_GVEC_TRANS(vand_vv
, and)
1368 GEN_OPIVV_GVEC_TRANS(vor_vv
, or)
1369 GEN_OPIVV_GVEC_TRANS(vxor_vv
, xor)
1370 GEN_OPIVX_GVEC_TRANS(vand_vx
, ands
)
1371 GEN_OPIVX_GVEC_TRANS(vor_vx
, ors
)
1372 GEN_OPIVX_GVEC_TRANS(vxor_vx
, xors
)
1373 GEN_OPIVI_GVEC_TRANS(vand_vi
, 0, vand_vx
, andi
)
1374 GEN_OPIVI_GVEC_TRANS(vor_vi
, 0, vor_vx
, ori
)
1375 GEN_OPIVI_GVEC_TRANS(vxor_vi
, 0, vxor_vx
, xori
)
1377 /* Vector Single-Width Bit Shift Instructions */
1378 GEN_OPIVV_GVEC_TRANS(vsll_vv
, shlv
)
1379 GEN_OPIVV_GVEC_TRANS(vsrl_vv
, shrv
)
1380 GEN_OPIVV_GVEC_TRANS(vsra_vv
, sarv
)
1382 typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32
,
1383 uint32_t, uint32_t);
1386 do_opivx_gvec_shift(DisasContext
*s
, arg_rmrr
*a
, GVecGen2sFn32
*gvec_fn
,
1387 gen_helper_opivx
*fn
)
1389 if (!opivx_check(s
, a
)) {
1393 if (a
->vm
&& s
->vl_eq_vlmax
) {
1394 TCGv_i32 src1
= tcg_temp_new_i32();
1395 TCGv tmp
= tcg_temp_new();
1397 gen_get_gpr(tmp
, a
->rs1
);
1398 tcg_gen_trunc_tl_i32(src1
, tmp
);
1399 tcg_gen_extract_i32(src1
, src1
, 0, s
->sew
+ 3);
1400 gvec_fn(s
->sew
, vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs2
),
1401 src1
, MAXSZ(s
), MAXSZ(s
));
1403 tcg_temp_free_i32(src1
);
1407 return opivx_trans(a
->rd
, a
->rs1
, a
->rs2
, a
->vm
, fn
, s
);
1410 #define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \
1411 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1413 static gen_helper_opivx * const fns[4] = { \
1414 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
1415 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
1418 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \
1421 GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx
, shls
)
1422 GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx
, shrs
)
1423 GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx
, sars
)
1425 GEN_OPIVI_GVEC_TRANS(vsll_vi
, 1, vsll_vx
, shli
)
1426 GEN_OPIVI_GVEC_TRANS(vsrl_vi
, 1, vsrl_vx
, shri
)
1427 GEN_OPIVI_GVEC_TRANS(vsra_vi
, 1, vsra_vx
, sari
)
1429 /* Vector Narrowing Integer Right Shift Instructions */
1430 static bool opivv_narrow_check(DisasContext
*s
, arg_rmrr
*a
)
1432 return (vext_check_isa_ill(s
) &&
1433 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1434 vext_check_reg(s
, a
->rd
, false) &&
1435 vext_check_reg(s
, a
->rs2
, true) &&
1436 vext_check_reg(s
, a
->rs1
, false) &&
1437 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
1439 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1442 /* OPIVV with NARROW */
1443 #define GEN_OPIVV_NARROW_TRANS(NAME) \
1444 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1446 if (opivv_narrow_check(s, a)) { \
1447 uint32_t data = 0; \
1448 static gen_helper_gvec_4_ptr * const fns[3] = { \
1449 gen_helper_##NAME##_b, \
1450 gen_helper_##NAME##_h, \
1451 gen_helper_##NAME##_w, \
1453 TCGLabel *over = gen_new_label(); \
1454 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1456 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1457 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1458 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1459 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1460 vreg_ofs(s, a->rs1), \
1461 vreg_ofs(s, a->rs2), cpu_env, 0, \
1462 s->vlen / 8, data, fns[s->sew]); \
1463 gen_set_label(over); \
1468 GEN_OPIVV_NARROW_TRANS(vnsra_vv
)
1469 GEN_OPIVV_NARROW_TRANS(vnsrl_vv
)
1471 static bool opivx_narrow_check(DisasContext
*s
, arg_rmrr
*a
)
1473 return (vext_check_isa_ill(s
) &&
1474 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1475 vext_check_reg(s
, a
->rd
, false) &&
1476 vext_check_reg(s
, a
->rs2
, true) &&
1477 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
1479 (s
->lmul
< 0x3) && (s
->sew
< 0x3));
1482 /* OPIVX with NARROW */
1483 #define GEN_OPIVX_NARROW_TRANS(NAME) \
1484 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1486 if (opivx_narrow_check(s, a)) { \
1487 static gen_helper_opivx * const fns[3] = { \
1488 gen_helper_##NAME##_b, \
1489 gen_helper_##NAME##_h, \
1490 gen_helper_##NAME##_w, \
1492 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
1497 GEN_OPIVX_NARROW_TRANS(vnsra_vx
)
1498 GEN_OPIVX_NARROW_TRANS(vnsrl_vx
)
1500 /* OPIVI with NARROW */
1501 #define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \
1502 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1504 if (opivx_narrow_check(s, a)) { \
1505 static gen_helper_opivx * const fns[3] = { \
1506 gen_helper_##OPIVX##_b, \
1507 gen_helper_##OPIVX##_h, \
1508 gen_helper_##OPIVX##_w, \
1510 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
1511 fns[s->sew], s, ZX); \
1516 GEN_OPIVI_NARROW_TRANS(vnsra_vi
, 1, vnsra_vx
)
1517 GEN_OPIVI_NARROW_TRANS(vnsrl_vi
, 1, vnsrl_vx
)
1519 /* Vector Integer Comparison Instructions */
1521 * For all comparison instructions, an illegal instruction exception is raised
1522 * if the destination vector register overlaps a source vector register group
1525 static bool opivv_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
1527 return (vext_check_isa_ill(s
) &&
1528 vext_check_reg(s
, a
->rs2
, false) &&
1529 vext_check_reg(s
, a
->rs1
, false) &&
1530 ((vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
1531 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
)) ||
1534 GEN_OPIVV_TRANS(vmseq_vv
, opivv_cmp_check
)
1535 GEN_OPIVV_TRANS(vmsne_vv
, opivv_cmp_check
)
1536 GEN_OPIVV_TRANS(vmsltu_vv
, opivv_cmp_check
)
1537 GEN_OPIVV_TRANS(vmslt_vv
, opivv_cmp_check
)
1538 GEN_OPIVV_TRANS(vmsleu_vv
, opivv_cmp_check
)
1539 GEN_OPIVV_TRANS(vmsle_vv
, opivv_cmp_check
)
1541 static bool opivx_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
1543 return (vext_check_isa_ill(s
) &&
1544 vext_check_reg(s
, a
->rs2
, false) &&
1545 (vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
) ||
1549 GEN_OPIVX_TRANS(vmseq_vx
, opivx_cmp_check
)
1550 GEN_OPIVX_TRANS(vmsne_vx
, opivx_cmp_check
)
1551 GEN_OPIVX_TRANS(vmsltu_vx
, opivx_cmp_check
)
1552 GEN_OPIVX_TRANS(vmslt_vx
, opivx_cmp_check
)
1553 GEN_OPIVX_TRANS(vmsleu_vx
, opivx_cmp_check
)
1554 GEN_OPIVX_TRANS(vmsle_vx
, opivx_cmp_check
)
1555 GEN_OPIVX_TRANS(vmsgtu_vx
, opivx_cmp_check
)
1556 GEN_OPIVX_TRANS(vmsgt_vx
, opivx_cmp_check
)
1558 GEN_OPIVI_TRANS(vmseq_vi
, 0, vmseq_vx
, opivx_cmp_check
)
1559 GEN_OPIVI_TRANS(vmsne_vi
, 0, vmsne_vx
, opivx_cmp_check
)
1560 GEN_OPIVI_TRANS(vmsleu_vi
, 1, vmsleu_vx
, opivx_cmp_check
)
1561 GEN_OPIVI_TRANS(vmsle_vi
, 0, vmsle_vx
, opivx_cmp_check
)
1562 GEN_OPIVI_TRANS(vmsgtu_vi
, 1, vmsgtu_vx
, opivx_cmp_check
)
1563 GEN_OPIVI_TRANS(vmsgt_vi
, 0, vmsgt_vx
, opivx_cmp_check
)
1565 /* Vector Integer Min/Max Instructions */
1566 GEN_OPIVV_GVEC_TRANS(vminu_vv
, umin
)
1567 GEN_OPIVV_GVEC_TRANS(vmin_vv
, smin
)
1568 GEN_OPIVV_GVEC_TRANS(vmaxu_vv
, umax
)
1569 GEN_OPIVV_GVEC_TRANS(vmax_vv
, smax
)
1570 GEN_OPIVX_TRANS(vminu_vx
, opivx_check
)
1571 GEN_OPIVX_TRANS(vmin_vx
, opivx_check
)
1572 GEN_OPIVX_TRANS(vmaxu_vx
, opivx_check
)
1573 GEN_OPIVX_TRANS(vmax_vx
, opivx_check
)
1575 /* Vector Single-Width Integer Multiply Instructions */
1576 GEN_OPIVV_GVEC_TRANS(vmul_vv
, mul
)
1577 GEN_OPIVV_TRANS(vmulh_vv
, opivv_check
)
1578 GEN_OPIVV_TRANS(vmulhu_vv
, opivv_check
)
1579 GEN_OPIVV_TRANS(vmulhsu_vv
, opivv_check
)
1580 GEN_OPIVX_GVEC_TRANS(vmul_vx
, muls
)
1581 GEN_OPIVX_TRANS(vmulh_vx
, opivx_check
)
1582 GEN_OPIVX_TRANS(vmulhu_vx
, opivx_check
)
1583 GEN_OPIVX_TRANS(vmulhsu_vx
, opivx_check
)
1585 /* Vector Integer Divide Instructions */
1586 GEN_OPIVV_TRANS(vdivu_vv
, opivv_check
)
1587 GEN_OPIVV_TRANS(vdiv_vv
, opivv_check
)
1588 GEN_OPIVV_TRANS(vremu_vv
, opivv_check
)
1589 GEN_OPIVV_TRANS(vrem_vv
, opivv_check
)
1590 GEN_OPIVX_TRANS(vdivu_vx
, opivx_check
)
1591 GEN_OPIVX_TRANS(vdiv_vx
, opivx_check
)
1592 GEN_OPIVX_TRANS(vremu_vx
, opivx_check
)
1593 GEN_OPIVX_TRANS(vrem_vx
, opivx_check
)
1595 /* Vector Widening Integer Multiply Instructions */
1596 GEN_OPIVV_WIDEN_TRANS(vwmul_vv
, opivv_widen_check
)
1597 GEN_OPIVV_WIDEN_TRANS(vwmulu_vv
, opivv_widen_check
)
1598 GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv
, opivv_widen_check
)
1599 GEN_OPIVX_WIDEN_TRANS(vwmul_vx
)
1600 GEN_OPIVX_WIDEN_TRANS(vwmulu_vx
)
1601 GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx
)
1603 /* Vector Single-Width Integer Multiply-Add Instructions */
1604 GEN_OPIVV_TRANS(vmacc_vv
, opivv_check
)
1605 GEN_OPIVV_TRANS(vnmsac_vv
, opivv_check
)
1606 GEN_OPIVV_TRANS(vmadd_vv
, opivv_check
)
1607 GEN_OPIVV_TRANS(vnmsub_vv
, opivv_check
)
1608 GEN_OPIVX_TRANS(vmacc_vx
, opivx_check
)
1609 GEN_OPIVX_TRANS(vnmsac_vx
, opivx_check
)
1610 GEN_OPIVX_TRANS(vmadd_vx
, opivx_check
)
1611 GEN_OPIVX_TRANS(vnmsub_vx
, opivx_check
)
1613 /* Vector Widening Integer Multiply-Add Instructions */
1614 GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv
, opivv_widen_check
)
1615 GEN_OPIVV_WIDEN_TRANS(vwmacc_vv
, opivv_widen_check
)
1616 GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv
, opivv_widen_check
)
1617 GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx
)
1618 GEN_OPIVX_WIDEN_TRANS(vwmacc_vx
)
1619 GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx
)
1620 GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx
)
1622 /* Vector Integer Merge and Move Instructions */
1623 static bool trans_vmv_v_v(DisasContext
*s
, arg_vmv_v_v
*a
)
1625 if (vext_check_isa_ill(s
) &&
1626 vext_check_reg(s
, a
->rd
, false) &&
1627 vext_check_reg(s
, a
->rs1
, false)) {
1629 if (s
->vl_eq_vlmax
) {
1630 tcg_gen_gvec_mov(s
->sew
, vreg_ofs(s
, a
->rd
),
1631 vreg_ofs(s
, a
->rs1
),
1632 MAXSZ(s
), MAXSZ(s
));
1634 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1635 static gen_helper_gvec_2_ptr
* const fns
[4] = {
1636 gen_helper_vmv_v_v_b
, gen_helper_vmv_v_v_h
,
1637 gen_helper_vmv_v_v_w
, gen_helper_vmv_v_v_d
,
1639 TCGLabel
*over
= gen_new_label();
1640 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1642 tcg_gen_gvec_2_ptr(vreg_ofs(s
, a
->rd
), vreg_ofs(s
, a
->rs1
),
1643 cpu_env
, 0, s
->vlen
/ 8, data
, fns
[s
->sew
]);
1644 gen_set_label(over
);
1651 typedef void gen_helper_vmv_vx(TCGv_ptr
, TCGv_i64
, TCGv_env
, TCGv_i32
);
1652 static bool trans_vmv_v_x(DisasContext
*s
, arg_vmv_v_x
*a
)
1654 if (vext_check_isa_ill(s
) &&
1655 vext_check_reg(s
, a
->rd
, false)) {
1658 TCGLabel
*over
= gen_new_label();
1659 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1661 s1
= tcg_temp_new();
1662 gen_get_gpr(s1
, a
->rs1
);
1664 if (s
->vl_eq_vlmax
) {
1665 tcg_gen_gvec_dup_tl(s
->sew
, vreg_ofs(s
, a
->rd
),
1666 MAXSZ(s
), MAXSZ(s
), s1
);
1669 TCGv_i64 s1_i64
= tcg_temp_new_i64();
1670 TCGv_ptr dest
= tcg_temp_new_ptr();
1671 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1672 static gen_helper_vmv_vx
* const fns
[4] = {
1673 gen_helper_vmv_v_x_b
, gen_helper_vmv_v_x_h
,
1674 gen_helper_vmv_v_x_w
, gen_helper_vmv_v_x_d
,
1677 tcg_gen_ext_tl_i64(s1_i64
, s1
);
1678 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1679 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
1680 fns
[s
->sew
](dest
, s1_i64
, cpu_env
, desc
);
1682 tcg_temp_free_ptr(dest
);
1683 tcg_temp_free_i32(desc
);
1684 tcg_temp_free_i64(s1_i64
);
1688 gen_set_label(over
);
1694 static bool trans_vmv_v_i(DisasContext
*s
, arg_vmv_v_i
*a
)
1696 if (vext_check_isa_ill(s
) &&
1697 vext_check_reg(s
, a
->rd
, false)) {
1699 int64_t simm
= sextract64(a
->rs1
, 0, 5);
1700 if (s
->vl_eq_vlmax
) {
1701 tcg_gen_gvec_dup_imm(s
->sew
, vreg_ofs(s
, a
->rd
),
1702 MAXSZ(s
), MAXSZ(s
), simm
);
1707 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
1708 static gen_helper_vmv_vx
* const fns
[4] = {
1709 gen_helper_vmv_v_x_b
, gen_helper_vmv_v_x_h
,
1710 gen_helper_vmv_v_x_w
, gen_helper_vmv_v_x_d
,
1712 TCGLabel
*over
= gen_new_label();
1713 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1715 s1
= tcg_const_i64(simm
);
1716 dest
= tcg_temp_new_ptr();
1717 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1718 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
1719 fns
[s
->sew
](dest
, s1
, cpu_env
, desc
);
1721 tcg_temp_free_ptr(dest
);
1722 tcg_temp_free_i32(desc
);
1723 tcg_temp_free_i64(s1
);
1724 gen_set_label(over
);
1731 GEN_OPIVV_TRANS(vmerge_vvm
, opivv_vadc_check
)
1732 GEN_OPIVX_TRANS(vmerge_vxm
, opivx_vadc_check
)
1733 GEN_OPIVI_TRANS(vmerge_vim
, 0, vmerge_vxm
, opivx_vadc_check
)
1736 *** Vector Fixed-Point Arithmetic Instructions
1739 /* Vector Single-Width Saturating Add and Subtract */
1740 GEN_OPIVV_TRANS(vsaddu_vv
, opivv_check
)
1741 GEN_OPIVV_TRANS(vsadd_vv
, opivv_check
)
1742 GEN_OPIVV_TRANS(vssubu_vv
, opivv_check
)
1743 GEN_OPIVV_TRANS(vssub_vv
, opivv_check
)
1744 GEN_OPIVX_TRANS(vsaddu_vx
, opivx_check
)
1745 GEN_OPIVX_TRANS(vsadd_vx
, opivx_check
)
1746 GEN_OPIVX_TRANS(vssubu_vx
, opivx_check
)
1747 GEN_OPIVX_TRANS(vssub_vx
, opivx_check
)
1748 GEN_OPIVI_TRANS(vsaddu_vi
, 1, vsaddu_vx
, opivx_check
)
1749 GEN_OPIVI_TRANS(vsadd_vi
, 0, vsadd_vx
, opivx_check
)
1751 /* Vector Single-Width Averaging Add and Subtract */
1752 GEN_OPIVV_TRANS(vaadd_vv
, opivv_check
)
1753 GEN_OPIVV_TRANS(vasub_vv
, opivv_check
)
1754 GEN_OPIVX_TRANS(vaadd_vx
, opivx_check
)
1755 GEN_OPIVX_TRANS(vasub_vx
, opivx_check
)
1756 GEN_OPIVI_TRANS(vaadd_vi
, 0, vaadd_vx
, opivx_check
)
1758 /* Vector Single-Width Fractional Multiply with Rounding and Saturation */
1759 GEN_OPIVV_TRANS(vsmul_vv
, opivv_check
)
1760 GEN_OPIVX_TRANS(vsmul_vx
, opivx_check
)
1762 /* Vector Widening Saturating Scaled Multiply-Add */
1763 GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv
, opivv_widen_check
)
1764 GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv
, opivv_widen_check
)
1765 GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv
, opivv_widen_check
)
1766 GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx
)
1767 GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx
)
1768 GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx
)
1769 GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx
)
1771 /* Vector Single-Width Scaling Shift Instructions */
1772 GEN_OPIVV_TRANS(vssrl_vv
, opivv_check
)
1773 GEN_OPIVV_TRANS(vssra_vv
, opivv_check
)
1774 GEN_OPIVX_TRANS(vssrl_vx
, opivx_check
)
1775 GEN_OPIVX_TRANS(vssra_vx
, opivx_check
)
1776 GEN_OPIVI_TRANS(vssrl_vi
, 1, vssrl_vx
, opivx_check
)
1777 GEN_OPIVI_TRANS(vssra_vi
, 0, vssra_vx
, opivx_check
)
1779 /* Vector Narrowing Fixed-Point Clip Instructions */
1780 GEN_OPIVV_NARROW_TRANS(vnclipu_vv
)
1781 GEN_OPIVV_NARROW_TRANS(vnclip_vv
)
1782 GEN_OPIVX_NARROW_TRANS(vnclipu_vx
)
1783 GEN_OPIVX_NARROW_TRANS(vnclip_vx
)
1784 GEN_OPIVI_NARROW_TRANS(vnclipu_vi
, 1, vnclipu_vx
)
1785 GEN_OPIVI_NARROW_TRANS(vnclip_vi
, 1, vnclip_vx
)
1788 *** Vector Float Point Arithmetic Instructions
1790 /* Vector Single-Width Floating-Point Add/Subtract Instructions */
1793 * If the current SEW does not correspond to a supported IEEE floating-point
1794 * type, an illegal instruction exception is raised.
1796 static bool opfvv_check(DisasContext
*s
, arg_rmrr
*a
)
1798 return (vext_check_isa_ill(s
) &&
1799 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1800 vext_check_reg(s
, a
->rd
, false) &&
1801 vext_check_reg(s
, a
->rs2
, false) &&
1802 vext_check_reg(s
, a
->rs1
, false) &&
1806 /* OPFVV without GVEC IR */
1807 #define GEN_OPFVV_TRANS(NAME, CHECK) \
1808 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1810 if (CHECK(s, a)) { \
1811 uint32_t data = 0; \
1812 static gen_helper_gvec_4_ptr * const fns[3] = { \
1813 gen_helper_##NAME##_h, \
1814 gen_helper_##NAME##_w, \
1815 gen_helper_##NAME##_d, \
1817 TCGLabel *over = gen_new_label(); \
1819 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1821 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1822 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1823 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1824 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1825 vreg_ofs(s, a->rs1), \
1826 vreg_ofs(s, a->rs2), cpu_env, 0, \
1827 s->vlen / 8, data, fns[s->sew - 1]); \
1828 gen_set_label(over); \
1833 GEN_OPFVV_TRANS(vfadd_vv
, opfvv_check
)
1834 GEN_OPFVV_TRANS(vfsub_vv
, opfvv_check
)
1836 typedef void gen_helper_opfvf(TCGv_ptr
, TCGv_ptr
, TCGv_i64
, TCGv_ptr
,
1837 TCGv_env
, TCGv_i32
);
1839 static bool opfvf_trans(uint32_t vd
, uint32_t rs1
, uint32_t vs2
,
1840 uint32_t data
, gen_helper_opfvf
*fn
, DisasContext
*s
)
1842 TCGv_ptr dest
, src2
, mask
;
1845 TCGLabel
*over
= gen_new_label();
1846 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
1848 dest
= tcg_temp_new_ptr();
1849 mask
= tcg_temp_new_ptr();
1850 src2
= tcg_temp_new_ptr();
1851 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
1853 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, vd
));
1854 tcg_gen_addi_ptr(src2
, cpu_env
, vreg_ofs(s
, vs2
));
1855 tcg_gen_addi_ptr(mask
, cpu_env
, vreg_ofs(s
, 0));
1857 fn(dest
, mask
, cpu_fpr
[rs1
], src2
, cpu_env
, desc
);
1859 tcg_temp_free_ptr(dest
);
1860 tcg_temp_free_ptr(mask
);
1861 tcg_temp_free_ptr(src2
);
1862 tcg_temp_free_i32(desc
);
1863 gen_set_label(over
);
1867 static bool opfvf_check(DisasContext
*s
, arg_rmrr
*a
)
1870 * If the current SEW does not correspond to a supported IEEE floating-point
1871 * type, an illegal instruction exception is raised
1873 return (vext_check_isa_ill(s
) &&
1874 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
1875 vext_check_reg(s
, a
->rd
, false) &&
1876 vext_check_reg(s
, a
->rs2
, false) &&
1880 /* OPFVF without GVEC IR */
1881 #define GEN_OPFVF_TRANS(NAME, CHECK) \
1882 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1884 if (CHECK(s, a)) { \
1885 uint32_t data = 0; \
1886 static gen_helper_opfvf *const fns[3] = { \
1887 gen_helper_##NAME##_h, \
1888 gen_helper_##NAME##_w, \
1889 gen_helper_##NAME##_d, \
1892 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1893 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1894 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1895 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
1896 fns[s->sew - 1], s); \
1901 GEN_OPFVF_TRANS(vfadd_vf
, opfvf_check
)
1902 GEN_OPFVF_TRANS(vfsub_vf
, opfvf_check
)
1903 GEN_OPFVF_TRANS(vfrsub_vf
, opfvf_check
)
1905 /* Vector Widening Floating-Point Add/Subtract Instructions */
1906 static bool opfvv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1908 return (vext_check_isa_ill(s
) &&
1909 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1910 vext_check_reg(s
, a
->rd
, true) &&
1911 vext_check_reg(s
, a
->rs2
, false) &&
1912 vext_check_reg(s
, a
->rs1
, false) &&
1913 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1915 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1917 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
1920 /* OPFVV with WIDEN */
1921 #define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \
1922 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1924 if (CHECK(s, a)) { \
1925 uint32_t data = 0; \
1926 static gen_helper_gvec_4_ptr * const fns[2] = { \
1927 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
1929 TCGLabel *over = gen_new_label(); \
1931 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
1933 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1934 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1935 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1936 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
1937 vreg_ofs(s, a->rs1), \
1938 vreg_ofs(s, a->rs2), cpu_env, 0, \
1939 s->vlen / 8, data, fns[s->sew - 1]); \
1940 gen_set_label(over); \
1946 GEN_OPFVV_WIDEN_TRANS(vfwadd_vv
, opfvv_widen_check
)
1947 GEN_OPFVV_WIDEN_TRANS(vfwsub_vv
, opfvv_widen_check
)
1949 static bool opfvf_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1951 return (vext_check_isa_ill(s
) &&
1952 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1953 vext_check_reg(s
, a
->rd
, true) &&
1954 vext_check_reg(s
, a
->rs2
, false) &&
1955 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
1957 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
1960 /* OPFVF with WIDEN */
1961 #define GEN_OPFVF_WIDEN_TRANS(NAME) \
1962 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1964 if (opfvf_widen_check(s, a)) { \
1965 uint32_t data = 0; \
1966 static gen_helper_opfvf *const fns[2] = { \
1967 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
1970 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
1971 data = FIELD_DP32(data, VDATA, VM, a->vm); \
1972 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
1973 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
1974 fns[s->sew - 1], s); \
1979 GEN_OPFVF_WIDEN_TRANS(vfwadd_vf
)
1980 GEN_OPFVF_WIDEN_TRANS(vfwsub_vf
)
1982 static bool opfwv_widen_check(DisasContext
*s
, arg_rmrr
*a
)
1984 return (vext_check_isa_ill(s
) &&
1985 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
1986 vext_check_reg(s
, a
->rd
, true) &&
1987 vext_check_reg(s
, a
->rs2
, true) &&
1988 vext_check_reg(s
, a
->rs1
, false) &&
1989 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs1
,
1991 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
1994 /* WIDEN OPFVV with WIDEN */
1995 #define GEN_OPFWV_WIDEN_TRANS(NAME) \
1996 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
1998 if (opfwv_widen_check(s, a)) { \
1999 uint32_t data = 0; \
2000 static gen_helper_gvec_4_ptr * const fns[2] = { \
2001 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
2003 TCGLabel *over = gen_new_label(); \
2005 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2007 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2008 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2009 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2010 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2011 vreg_ofs(s, a->rs1), \
2012 vreg_ofs(s, a->rs2), cpu_env, 0, \
2013 s->vlen / 8, data, fns[s->sew - 1]); \
2014 gen_set_label(over); \
2020 GEN_OPFWV_WIDEN_TRANS(vfwadd_wv
)
2021 GEN_OPFWV_WIDEN_TRANS(vfwsub_wv
)
2023 static bool opfwf_widen_check(DisasContext
*s
, arg_rmrr
*a
)
2025 return (vext_check_isa_ill(s
) &&
2026 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2027 vext_check_reg(s
, a
->rd
, true) &&
2028 vext_check_reg(s
, a
->rs2
, true) &&
2029 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2032 /* WIDEN OPFVF with WIDEN */
2033 #define GEN_OPFWF_WIDEN_TRANS(NAME) \
2034 static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
2036 if (opfwf_widen_check(s, a)) { \
2037 uint32_t data = 0; \
2038 static gen_helper_opfvf *const fns[2] = { \
2039 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \
2042 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2043 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2044 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2045 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \
2046 fns[s->sew - 1], s); \
2051 GEN_OPFWF_WIDEN_TRANS(vfwadd_wf
)
2052 GEN_OPFWF_WIDEN_TRANS(vfwsub_wf
)
2054 /* Vector Single-Width Floating-Point Multiply/Divide Instructions */
2055 GEN_OPFVV_TRANS(vfmul_vv
, opfvv_check
)
2056 GEN_OPFVV_TRANS(vfdiv_vv
, opfvv_check
)
2057 GEN_OPFVF_TRANS(vfmul_vf
, opfvf_check
)
2058 GEN_OPFVF_TRANS(vfdiv_vf
, opfvf_check
)
2059 GEN_OPFVF_TRANS(vfrdiv_vf
, opfvf_check
)
2061 /* Vector Widening Floating-Point Multiply */
2062 GEN_OPFVV_WIDEN_TRANS(vfwmul_vv
, opfvv_widen_check
)
2063 GEN_OPFVF_WIDEN_TRANS(vfwmul_vf
)
2065 /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */
2066 GEN_OPFVV_TRANS(vfmacc_vv
, opfvv_check
)
2067 GEN_OPFVV_TRANS(vfnmacc_vv
, opfvv_check
)
2068 GEN_OPFVV_TRANS(vfmsac_vv
, opfvv_check
)
2069 GEN_OPFVV_TRANS(vfnmsac_vv
, opfvv_check
)
2070 GEN_OPFVV_TRANS(vfmadd_vv
, opfvv_check
)
2071 GEN_OPFVV_TRANS(vfnmadd_vv
, opfvv_check
)
2072 GEN_OPFVV_TRANS(vfmsub_vv
, opfvv_check
)
2073 GEN_OPFVV_TRANS(vfnmsub_vv
, opfvv_check
)
2074 GEN_OPFVF_TRANS(vfmacc_vf
, opfvf_check
)
2075 GEN_OPFVF_TRANS(vfnmacc_vf
, opfvf_check
)
2076 GEN_OPFVF_TRANS(vfmsac_vf
, opfvf_check
)
2077 GEN_OPFVF_TRANS(vfnmsac_vf
, opfvf_check
)
2078 GEN_OPFVF_TRANS(vfmadd_vf
, opfvf_check
)
2079 GEN_OPFVF_TRANS(vfnmadd_vf
, opfvf_check
)
2080 GEN_OPFVF_TRANS(vfmsub_vf
, opfvf_check
)
2081 GEN_OPFVF_TRANS(vfnmsub_vf
, opfvf_check
)
2083 /* Vector Widening Floating-Point Fused Multiply-Add Instructions */
2084 GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv
, opfvv_widen_check
)
2085 GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv
, opfvv_widen_check
)
2086 GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv
, opfvv_widen_check
)
2087 GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv
, opfvv_widen_check
)
2088 GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf
)
2089 GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf
)
2090 GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf
)
2091 GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf
)
2093 /* Vector Floating-Point Square-Root Instruction */
2096 * If the current SEW does not correspond to a supported IEEE floating-point
2097 * type, an illegal instruction exception is raised
2099 static bool opfv_check(DisasContext
*s
, arg_rmr
*a
)
2101 return (vext_check_isa_ill(s
) &&
2102 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
2103 vext_check_reg(s
, a
->rd
, false) &&
2104 vext_check_reg(s
, a
->rs2
, false) &&
2108 #define GEN_OPFV_TRANS(NAME, CHECK) \
2109 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2111 if (CHECK(s, a)) { \
2112 uint32_t data = 0; \
2113 static gen_helper_gvec_3_ptr * const fns[3] = { \
2114 gen_helper_##NAME##_h, \
2115 gen_helper_##NAME##_w, \
2116 gen_helper_##NAME##_d, \
2118 TCGLabel *over = gen_new_label(); \
2120 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2122 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2123 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2124 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2125 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2126 vreg_ofs(s, a->rs2), cpu_env, 0, \
2127 s->vlen / 8, data, fns[s->sew - 1]); \
2128 gen_set_label(over); \
2134 GEN_OPFV_TRANS(vfsqrt_v
, opfv_check
)
2136 /* Vector Floating-Point MIN/MAX Instructions */
2137 GEN_OPFVV_TRANS(vfmin_vv
, opfvv_check
)
2138 GEN_OPFVV_TRANS(vfmax_vv
, opfvv_check
)
2139 GEN_OPFVF_TRANS(vfmin_vf
, opfvf_check
)
2140 GEN_OPFVF_TRANS(vfmax_vf
, opfvf_check
)
2142 /* Vector Floating-Point Sign-Injection Instructions */
2143 GEN_OPFVV_TRANS(vfsgnj_vv
, opfvv_check
)
2144 GEN_OPFVV_TRANS(vfsgnjn_vv
, opfvv_check
)
2145 GEN_OPFVV_TRANS(vfsgnjx_vv
, opfvv_check
)
2146 GEN_OPFVF_TRANS(vfsgnj_vf
, opfvf_check
)
2147 GEN_OPFVF_TRANS(vfsgnjn_vf
, opfvf_check
)
2148 GEN_OPFVF_TRANS(vfsgnjx_vf
, opfvf_check
)
2150 /* Vector Floating-Point Compare Instructions */
2151 static bool opfvv_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
2153 return (vext_check_isa_ill(s
) &&
2154 vext_check_reg(s
, a
->rs2
, false) &&
2155 vext_check_reg(s
, a
->rs1
, false) &&
2157 ((vext_check_overlap_group(a
->rd
, 1, a
->rs1
, 1 << s
->lmul
) &&
2158 vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
)) ||
2162 GEN_OPFVV_TRANS(vmfeq_vv
, opfvv_cmp_check
)
2163 GEN_OPFVV_TRANS(vmfne_vv
, opfvv_cmp_check
)
2164 GEN_OPFVV_TRANS(vmflt_vv
, opfvv_cmp_check
)
2165 GEN_OPFVV_TRANS(vmfle_vv
, opfvv_cmp_check
)
2166 GEN_OPFVV_TRANS(vmford_vv
, opfvv_cmp_check
)
2168 static bool opfvf_cmp_check(DisasContext
*s
, arg_rmrr
*a
)
2170 return (vext_check_isa_ill(s
) &&
2171 vext_check_reg(s
, a
->rs2
, false) &&
2173 (vext_check_overlap_group(a
->rd
, 1, a
->rs2
, 1 << s
->lmul
) ||
2177 GEN_OPFVF_TRANS(vmfeq_vf
, opfvf_cmp_check
)
2178 GEN_OPFVF_TRANS(vmfne_vf
, opfvf_cmp_check
)
2179 GEN_OPFVF_TRANS(vmflt_vf
, opfvf_cmp_check
)
2180 GEN_OPFVF_TRANS(vmfle_vf
, opfvf_cmp_check
)
2181 GEN_OPFVF_TRANS(vmfgt_vf
, opfvf_cmp_check
)
2182 GEN_OPFVF_TRANS(vmfge_vf
, opfvf_cmp_check
)
2183 GEN_OPFVF_TRANS(vmford_vf
, opfvf_cmp_check
)
2185 /* Vector Floating-Point Classify Instruction */
2186 GEN_OPFV_TRANS(vfclass_v
, opfv_check
)
2188 /* Vector Floating-Point Merge Instruction */
2189 GEN_OPFVF_TRANS(vfmerge_vfm
, opfvf_check
)
2191 static bool trans_vfmv_v_f(DisasContext
*s
, arg_vfmv_v_f
*a
)
2193 if (vext_check_isa_ill(s
) &&
2194 vext_check_reg(s
, a
->rd
, false) &&
2197 if (s
->vl_eq_vlmax
) {
2198 tcg_gen_gvec_dup_i64(s
->sew
, vreg_ofs(s
, a
->rd
),
2199 MAXSZ(s
), MAXSZ(s
), cpu_fpr
[a
->rs1
]);
2203 uint32_t data
= FIELD_DP32(0, VDATA
, LMUL
, s
->lmul
);
2204 static gen_helper_vmv_vx
* const fns
[3] = {
2205 gen_helper_vmv_v_x_h
,
2206 gen_helper_vmv_v_x_w
,
2207 gen_helper_vmv_v_x_d
,
2209 TCGLabel
*over
= gen_new_label();
2210 tcg_gen_brcondi_tl(TCG_COND_EQ
, cpu_vl
, 0, over
);
2212 dest
= tcg_temp_new_ptr();
2213 desc
= tcg_const_i32(simd_desc(0, s
->vlen
/ 8, data
));
2214 tcg_gen_addi_ptr(dest
, cpu_env
, vreg_ofs(s
, a
->rd
));
2215 fns
[s
->sew
- 1](dest
, cpu_fpr
[a
->rs1
], cpu_env
, desc
);
2217 tcg_temp_free_ptr(dest
);
2218 tcg_temp_free_i32(desc
);
2219 gen_set_label(over
);
2226 /* Single-Width Floating-Point/Integer Type-Convert Instructions */
2227 GEN_OPFV_TRANS(vfcvt_xu_f_v
, opfv_check
)
2228 GEN_OPFV_TRANS(vfcvt_x_f_v
, opfv_check
)
2229 GEN_OPFV_TRANS(vfcvt_f_xu_v
, opfv_check
)
2230 GEN_OPFV_TRANS(vfcvt_f_x_v
, opfv_check
)
2232 /* Widening Floating-Point/Integer Type-Convert Instructions */
2235 * If the current SEW does not correspond to a supported IEEE floating-point
2236 * type, an illegal instruction exception is raised
2238 static bool opfv_widen_check(DisasContext
*s
, arg_rmr
*a
)
2240 return (vext_check_isa_ill(s
) &&
2241 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, true) &&
2242 vext_check_reg(s
, a
->rd
, true) &&
2243 vext_check_reg(s
, a
->rs2
, false) &&
2244 vext_check_overlap_group(a
->rd
, 2 << s
->lmul
, a
->rs2
,
2246 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2249 #define GEN_OPFV_WIDEN_TRANS(NAME) \
2250 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2252 if (opfv_widen_check(s, a)) { \
2253 uint32_t data = 0; \
2254 static gen_helper_gvec_3_ptr * const fns[2] = { \
2255 gen_helper_##NAME##_h, \
2256 gen_helper_##NAME##_w, \
2258 TCGLabel *over = gen_new_label(); \
2260 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2262 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2263 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2264 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2265 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2266 vreg_ofs(s, a->rs2), cpu_env, 0, \
2267 s->vlen / 8, data, fns[s->sew - 1]); \
2268 gen_set_label(over); \
2274 GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v
)
2275 GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v
)
2276 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v
)
2277 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v
)
2278 GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v
)
2280 /* Narrowing Floating-Point/Integer Type-Convert Instructions */
2283 * If the current SEW does not correspond to a supported IEEE floating-point
2284 * type, an illegal instruction exception is raised
2286 static bool opfv_narrow_check(DisasContext
*s
, arg_rmr
*a
)
2288 return (vext_check_isa_ill(s
) &&
2289 vext_check_overlap_mask(s
, a
->rd
, a
->vm
, false) &&
2290 vext_check_reg(s
, a
->rd
, false) &&
2291 vext_check_reg(s
, a
->rs2
, true) &&
2292 vext_check_overlap_group(a
->rd
, 1 << s
->lmul
, a
->rs2
,
2294 (s
->lmul
< 0x3) && (s
->sew
< 0x3) && (s
->sew
!= 0));
2297 #define GEN_OPFV_NARROW_TRANS(NAME) \
2298 static bool trans_##NAME(DisasContext *s, arg_rmr *a) \
2300 if (opfv_narrow_check(s, a)) { \
2301 uint32_t data = 0; \
2302 static gen_helper_gvec_3_ptr * const fns[2] = { \
2303 gen_helper_##NAME##_h, \
2304 gen_helper_##NAME##_w, \
2306 TCGLabel *over = gen_new_label(); \
2308 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
2310 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
2311 data = FIELD_DP32(data, VDATA, VM, a->vm); \
2312 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
2313 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
2314 vreg_ofs(s, a->rs2), cpu_env, 0, \
2315 s->vlen / 8, data, fns[s->sew - 1]); \
2316 gen_set_label(over); \
2322 GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v
)
2323 GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v
)
2324 GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v
)
2325 GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v
)
2326 GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v
)
2329 *** Vector Reduction Operations
2331 /* Vector Single-Width Integer Reduction Instructions */
2332 static bool reduction_check(DisasContext
*s
, arg_rmrr
*a
)
2334 return vext_check_isa_ill(s
) && vext_check_reg(s
, a
->rs2
, false);
2337 GEN_OPIVV_TRANS(vredsum_vs
, reduction_check
)
2338 GEN_OPIVV_TRANS(vredmaxu_vs
, reduction_check
)
2339 GEN_OPIVV_TRANS(vredmax_vs
, reduction_check
)
2340 GEN_OPIVV_TRANS(vredminu_vs
, reduction_check
)
2341 GEN_OPIVV_TRANS(vredmin_vs
, reduction_check
)
2342 GEN_OPIVV_TRANS(vredand_vs
, reduction_check
)
2343 GEN_OPIVV_TRANS(vredor_vs
, reduction_check
)
2344 GEN_OPIVV_TRANS(vredxor_vs
, reduction_check
)