1/* 2 * RISC-V translation routines for the RVV Standard Extension. 3 * 4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18#include "tcg/tcg-op-gvec.h" 19#include "tcg/tcg-gvec-desc.h" 20#include "internals.h" 21 22static bool trans_vsetvl(DisasContext *ctx, arg_vsetvl *a) 23{ 24 TCGv s1, s2, dst; 25 26 if (!has_ext(ctx, RVV)) { 27 return false; 28 } 29 30 s2 = get_gpr(ctx, a->rs2, EXT_ZERO); 31 dst = dest_gpr(ctx, a->rd); 32 33 /* Using x0 as the rs1 register specifier, encodes an infinite AVL */ 34 if (a->rs1 == 0) { 35 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ 36 s1 = tcg_constant_tl(RV_VLEN_MAX); 37 } else { 38 s1 = get_gpr(ctx, a->rs1, EXT_ZERO); 39 } 40 gen_helper_vsetvl(dst, cpu_env, s1, s2); 41 gen_set_gpr(ctx, a->rd, dst); 42 mark_vs_dirty(ctx); 43 44 tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); 45 tcg_gen_lookup_and_goto_ptr(); 46 ctx->base.is_jmp = DISAS_NORETURN; 47 return true; 48} 49 50static bool trans_vsetvli(DisasContext *ctx, arg_vsetvli *a) 51{ 52 TCGv s1, s2, dst; 53 54 if (!has_ext(ctx, RVV)) { 55 return false; 56 } 57 58 s2 = tcg_constant_tl(a->zimm); 59 dst = dest_gpr(ctx, a->rd); 60 61 /* Using x0 as the rs1 register specifier, encodes an infinite AVL */ 62 if (a->rs1 == 0) { 63 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ 64 s1 = tcg_constant_tl(RV_VLEN_MAX); 65 } else { 66 s1 = get_gpr(ctx, a->rs1, EXT_ZERO); 67 } 68 gen_helper_vsetvl(dst, cpu_env, s1, s2); 69 gen_set_gpr(ctx, a->rd, dst); 70 mark_vs_dirty(ctx); 71 72 gen_goto_tb(ctx, 0, ctx->pc_succ_insn); 73 ctx->base.is_jmp = DISAS_NORETURN; 74 return true; 75} 76 77/* vector register offset from env */ 78static uint32_t vreg_ofs(DisasContext *s, int reg) 79{ 80 return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8; 81} 82 83/* check functions */ 84 85/* 86 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present. 87 * So RVV is also be checked in this function. 88 */ 89static bool vext_check_isa_ill(DisasContext *s) 90{ 91 return !s->vill; 92} 93 94/* 95 * There are two rules check here. 96 * 97 * 1. Vector register numbers are multiples of LMUL. (Section 3.2) 98 * 99 * 2. For all widening instructions, the destination LMUL value must also be 100 * a supported LMUL value. (Section 11.2) 101 */ 102static bool vext_check_reg(DisasContext *s, uint32_t reg, bool widen) 103{ 104 /* 105 * The destination vector register group results are arranged as if both 106 * SEW and LMUL were at twice their current settings. (Section 11.2). 107 */ 108 int legal = widen ? 2 << s->lmul : 1 << s->lmul; 109 110 return !((s->lmul == 0x3 && widen) || (reg % legal)); 111} 112 113/* 114 * There are two rules check here. 115 * 116 * 1. The destination vector register group for a masked vector instruction can 117 * only overlap the source mask register (v0) when LMUL=1. (Section 5.3) 118 * 119 * 2. In widen instructions and some other insturctions, like vslideup.vx, 120 * there is no need to check whether LMUL=1. 121 */ 122static bool vext_check_overlap_mask(DisasContext *s, uint32_t vd, bool vm, 123 bool force) 124{ 125 return (vm != 0 || vd != 0) || (!force && (s->lmul == 0)); 126} 127 128/* The LMUL setting must be such that LMUL * NFIELDS <= 8. (Section 7.8) */ 129static bool vext_check_nf(DisasContext *s, uint32_t nf) 130{ 131 return (1 << s->lmul) * nf <= 8; 132} 133 134/* 135 * The destination vector register group cannot overlap a source vector register 136 * group of a different element width. (Section 11.2) 137 */ 138static inline bool vext_check_overlap_group(int rd, int dlen, int rs, int slen) 139{ 140 return ((rd >= rs + slen) || (rs >= rd + dlen)); 141} 142/* common translation macro */ 143#define GEN_VEXT_TRANS(NAME, SEQ, ARGTYPE, OP, CHECK) \ 144static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE *a)\ 145{ \ 146 if (CHECK(s, a)) { \ 147 return OP(s, a, SEQ); \ 148 } \ 149 return false; \ 150} 151 152/* 153 *** unit stride load and store 154 */ 155typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv, 156 TCGv_env, TCGv_i32); 157 158static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, 159 gen_helper_ldst_us *fn, DisasContext *s, 160 bool is_store) 161{ 162 TCGv_ptr dest, mask; 163 TCGv base; 164 TCGv_i32 desc; 165 166 TCGLabel *over = gen_new_label(); 167 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 168 169 dest = tcg_temp_new_ptr(); 170 mask = tcg_temp_new_ptr(); 171 base = get_gpr(s, rs1, EXT_NONE); 172 173 /* 174 * As simd_desc supports at most 256 bytes, and in this implementation, 175 * the max vector group length is 2048 bytes. So split it into two parts. 176 * 177 * The first part is vlen in bytes, encoded in maxsz of simd_desc. 178 * The second part is lmul, encoded in data of simd_desc. 179 */ 180 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 181 182 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 183 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 184 185 fn(dest, mask, base, cpu_env, desc); 186 187 tcg_temp_free_ptr(dest); 188 tcg_temp_free_ptr(mask); 189 190 if (!is_store) { 191 mark_vs_dirty(s); 192 } 193 194 gen_set_label(over); 195 return true; 196} 197 198static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) 199{ 200 uint32_t data = 0; 201 gen_helper_ldst_us *fn; 202 static gen_helper_ldst_us * const fns[2][7][4] = { 203 /* masked unit stride load */ 204 { { gen_helper_vlb_v_b_mask, gen_helper_vlb_v_h_mask, 205 gen_helper_vlb_v_w_mask, gen_helper_vlb_v_d_mask }, 206 { NULL, gen_helper_vlh_v_h_mask, 207 gen_helper_vlh_v_w_mask, gen_helper_vlh_v_d_mask }, 208 { NULL, NULL, 209 gen_helper_vlw_v_w_mask, gen_helper_vlw_v_d_mask }, 210 { gen_helper_vle_v_b_mask, gen_helper_vle_v_h_mask, 211 gen_helper_vle_v_w_mask, gen_helper_vle_v_d_mask }, 212 { gen_helper_vlbu_v_b_mask, gen_helper_vlbu_v_h_mask, 213 gen_helper_vlbu_v_w_mask, gen_helper_vlbu_v_d_mask }, 214 { NULL, gen_helper_vlhu_v_h_mask, 215 gen_helper_vlhu_v_w_mask, gen_helper_vlhu_v_d_mask }, 216 { NULL, NULL, 217 gen_helper_vlwu_v_w_mask, gen_helper_vlwu_v_d_mask } }, 218 /* unmasked unit stride load */ 219 { { gen_helper_vlb_v_b, gen_helper_vlb_v_h, 220 gen_helper_vlb_v_w, gen_helper_vlb_v_d }, 221 { NULL, gen_helper_vlh_v_h, 222 gen_helper_vlh_v_w, gen_helper_vlh_v_d }, 223 { NULL, NULL, 224 gen_helper_vlw_v_w, gen_helper_vlw_v_d }, 225 { gen_helper_vle_v_b, gen_helper_vle_v_h, 226 gen_helper_vle_v_w, gen_helper_vle_v_d }, 227 { gen_helper_vlbu_v_b, gen_helper_vlbu_v_h, 228 gen_helper_vlbu_v_w, gen_helper_vlbu_v_d }, 229 { NULL, gen_helper_vlhu_v_h, 230 gen_helper_vlhu_v_w, gen_helper_vlhu_v_d }, 231 { NULL, NULL, 232 gen_helper_vlwu_v_w, gen_helper_vlwu_v_d } } 233 }; 234 235 fn = fns[a->vm][seq][s->sew]; 236 if (fn == NULL) { 237 return false; 238 } 239 240 data = FIELD_DP32(data, VDATA, VM, a->vm); 241 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 242 data = FIELD_DP32(data, VDATA, NF, a->nf); 243 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 244} 245 246static bool ld_us_check(DisasContext *s, arg_r2nfvm* a) 247{ 248 return (vext_check_isa_ill(s) && 249 vext_check_overlap_mask(s, a->rd, a->vm, false) && 250 vext_check_reg(s, a->rd, false) && 251 vext_check_nf(s, a->nf)); 252} 253 254GEN_VEXT_TRANS(vlb_v, 0, r2nfvm, ld_us_op, ld_us_check) 255GEN_VEXT_TRANS(vlh_v, 1, r2nfvm, ld_us_op, ld_us_check) 256GEN_VEXT_TRANS(vlw_v, 2, r2nfvm, ld_us_op, ld_us_check) 257GEN_VEXT_TRANS(vle_v, 3, r2nfvm, ld_us_op, ld_us_check) 258GEN_VEXT_TRANS(vlbu_v, 4, r2nfvm, ld_us_op, ld_us_check) 259GEN_VEXT_TRANS(vlhu_v, 5, r2nfvm, ld_us_op, ld_us_check) 260GEN_VEXT_TRANS(vlwu_v, 6, r2nfvm, ld_us_op, ld_us_check) 261 262static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) 263{ 264 uint32_t data = 0; 265 gen_helper_ldst_us *fn; 266 static gen_helper_ldst_us * const fns[2][4][4] = { 267 /* masked unit stride load and store */ 268 { { gen_helper_vsb_v_b_mask, gen_helper_vsb_v_h_mask, 269 gen_helper_vsb_v_w_mask, gen_helper_vsb_v_d_mask }, 270 { NULL, gen_helper_vsh_v_h_mask, 271 gen_helper_vsh_v_w_mask, gen_helper_vsh_v_d_mask }, 272 { NULL, NULL, 273 gen_helper_vsw_v_w_mask, gen_helper_vsw_v_d_mask }, 274 { gen_helper_vse_v_b_mask, gen_helper_vse_v_h_mask, 275 gen_helper_vse_v_w_mask, gen_helper_vse_v_d_mask } }, 276 /* unmasked unit stride store */ 277 { { gen_helper_vsb_v_b, gen_helper_vsb_v_h, 278 gen_helper_vsb_v_w, gen_helper_vsb_v_d }, 279 { NULL, gen_helper_vsh_v_h, 280 gen_helper_vsh_v_w, gen_helper_vsh_v_d }, 281 { NULL, NULL, 282 gen_helper_vsw_v_w, gen_helper_vsw_v_d }, 283 { gen_helper_vse_v_b, gen_helper_vse_v_h, 284 gen_helper_vse_v_w, gen_helper_vse_v_d } } 285 }; 286 287 fn = fns[a->vm][seq][s->sew]; 288 if (fn == NULL) { 289 return false; 290 } 291 292 data = FIELD_DP32(data, VDATA, VM, a->vm); 293 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 294 data = FIELD_DP32(data, VDATA, NF, a->nf); 295 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 296} 297 298static bool st_us_check(DisasContext *s, arg_r2nfvm* a) 299{ 300 return (vext_check_isa_ill(s) && 301 vext_check_reg(s, a->rd, false) && 302 vext_check_nf(s, a->nf)); 303} 304 305GEN_VEXT_TRANS(vsb_v, 0, r2nfvm, st_us_op, st_us_check) 306GEN_VEXT_TRANS(vsh_v, 1, r2nfvm, st_us_op, st_us_check) 307GEN_VEXT_TRANS(vsw_v, 2, r2nfvm, st_us_op, st_us_check) 308GEN_VEXT_TRANS(vse_v, 3, r2nfvm, st_us_op, st_us_check) 309 310/* 311 *** stride load and store 312 */ 313typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, 314 TCGv, TCGv_env, TCGv_i32); 315 316static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, 317 uint32_t data, gen_helper_ldst_stride *fn, 318 DisasContext *s, bool is_store) 319{ 320 TCGv_ptr dest, mask; 321 TCGv base, stride; 322 TCGv_i32 desc; 323 324 TCGLabel *over = gen_new_label(); 325 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 326 327 dest = tcg_temp_new_ptr(); 328 mask = tcg_temp_new_ptr(); 329 base = get_gpr(s, rs1, EXT_NONE); 330 stride = get_gpr(s, rs2, EXT_NONE); 331 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 332 333 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 334 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 335 336 fn(dest, mask, base, stride, cpu_env, desc); 337 338 tcg_temp_free_ptr(dest); 339 tcg_temp_free_ptr(mask); 340 341 if (!is_store) { 342 mark_vs_dirty(s); 343 } 344 345 gen_set_label(over); 346 return true; 347} 348 349static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) 350{ 351 uint32_t data = 0; 352 gen_helper_ldst_stride *fn; 353 static gen_helper_ldst_stride * const fns[7][4] = { 354 { gen_helper_vlsb_v_b, gen_helper_vlsb_v_h, 355 gen_helper_vlsb_v_w, gen_helper_vlsb_v_d }, 356 { NULL, gen_helper_vlsh_v_h, 357 gen_helper_vlsh_v_w, gen_helper_vlsh_v_d }, 358 { NULL, NULL, 359 gen_helper_vlsw_v_w, gen_helper_vlsw_v_d }, 360 { gen_helper_vlse_v_b, gen_helper_vlse_v_h, 361 gen_helper_vlse_v_w, gen_helper_vlse_v_d }, 362 { gen_helper_vlsbu_v_b, gen_helper_vlsbu_v_h, 363 gen_helper_vlsbu_v_w, gen_helper_vlsbu_v_d }, 364 { NULL, gen_helper_vlshu_v_h, 365 gen_helper_vlshu_v_w, gen_helper_vlshu_v_d }, 366 { NULL, NULL, 367 gen_helper_vlswu_v_w, gen_helper_vlswu_v_d }, 368 }; 369 370 fn = fns[seq][s->sew]; 371 if (fn == NULL) { 372 return false; 373 } 374 375 data = FIELD_DP32(data, VDATA, VM, a->vm); 376 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 377 data = FIELD_DP32(data, VDATA, NF, a->nf); 378 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 379} 380 381static bool ld_stride_check(DisasContext *s, arg_rnfvm* a) 382{ 383 return (vext_check_isa_ill(s) && 384 vext_check_overlap_mask(s, a->rd, a->vm, false) && 385 vext_check_reg(s, a->rd, false) && 386 vext_check_nf(s, a->nf)); 387} 388 389GEN_VEXT_TRANS(vlsb_v, 0, rnfvm, ld_stride_op, ld_stride_check) 390GEN_VEXT_TRANS(vlsh_v, 1, rnfvm, ld_stride_op, ld_stride_check) 391GEN_VEXT_TRANS(vlsw_v, 2, rnfvm, ld_stride_op, ld_stride_check) 392GEN_VEXT_TRANS(vlse_v, 3, rnfvm, ld_stride_op, ld_stride_check) 393GEN_VEXT_TRANS(vlsbu_v, 4, rnfvm, ld_stride_op, ld_stride_check) 394GEN_VEXT_TRANS(vlshu_v, 5, rnfvm, ld_stride_op, ld_stride_check) 395GEN_VEXT_TRANS(vlswu_v, 6, rnfvm, ld_stride_op, ld_stride_check) 396 397static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) 398{ 399 uint32_t data = 0; 400 gen_helper_ldst_stride *fn; 401 static gen_helper_ldst_stride * const fns[4][4] = { 402 /* masked stride store */ 403 { gen_helper_vssb_v_b, gen_helper_vssb_v_h, 404 gen_helper_vssb_v_w, gen_helper_vssb_v_d }, 405 { NULL, gen_helper_vssh_v_h, 406 gen_helper_vssh_v_w, gen_helper_vssh_v_d }, 407 { NULL, NULL, 408 gen_helper_vssw_v_w, gen_helper_vssw_v_d }, 409 { gen_helper_vsse_v_b, gen_helper_vsse_v_h, 410 gen_helper_vsse_v_w, gen_helper_vsse_v_d } 411 }; 412 413 data = FIELD_DP32(data, VDATA, VM, a->vm); 414 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 415 data = FIELD_DP32(data, VDATA, NF, a->nf); 416 fn = fns[seq][s->sew]; 417 if (fn == NULL) { 418 return false; 419 } 420 421 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); 422} 423 424static bool st_stride_check(DisasContext *s, arg_rnfvm* a) 425{ 426 return (vext_check_isa_ill(s) && 427 vext_check_reg(s, a->rd, false) && 428 vext_check_nf(s, a->nf)); 429} 430 431GEN_VEXT_TRANS(vssb_v, 0, rnfvm, st_stride_op, st_stride_check) 432GEN_VEXT_TRANS(vssh_v, 1, rnfvm, st_stride_op, st_stride_check) 433GEN_VEXT_TRANS(vssw_v, 2, rnfvm, st_stride_op, st_stride_check) 434GEN_VEXT_TRANS(vsse_v, 3, rnfvm, st_stride_op, st_stride_check) 435 436/* 437 *** index load and store 438 */ 439typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, 440 TCGv_ptr, TCGv_env, TCGv_i32); 441 442static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 443 uint32_t data, gen_helper_ldst_index *fn, 444 DisasContext *s, bool is_store) 445{ 446 TCGv_ptr dest, mask, index; 447 TCGv base; 448 TCGv_i32 desc; 449 450 TCGLabel *over = gen_new_label(); 451 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 452 453 dest = tcg_temp_new_ptr(); 454 mask = tcg_temp_new_ptr(); 455 index = tcg_temp_new_ptr(); 456 base = get_gpr(s, rs1, EXT_NONE); 457 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 458 459 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 460 tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); 461 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 462 463 fn(dest, mask, base, index, cpu_env, desc); 464 465 tcg_temp_free_ptr(dest); 466 tcg_temp_free_ptr(mask); 467 tcg_temp_free_ptr(index); 468 469 if (!is_store) { 470 mark_vs_dirty(s); 471 } 472 473 gen_set_label(over); 474 return true; 475} 476 477static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) 478{ 479 uint32_t data = 0; 480 gen_helper_ldst_index *fn; 481 static gen_helper_ldst_index * const fns[7][4] = { 482 { gen_helper_vlxb_v_b, gen_helper_vlxb_v_h, 483 gen_helper_vlxb_v_w, gen_helper_vlxb_v_d }, 484 { NULL, gen_helper_vlxh_v_h, 485 gen_helper_vlxh_v_w, gen_helper_vlxh_v_d }, 486 { NULL, NULL, 487 gen_helper_vlxw_v_w, gen_helper_vlxw_v_d }, 488 { gen_helper_vlxe_v_b, gen_helper_vlxe_v_h, 489 gen_helper_vlxe_v_w, gen_helper_vlxe_v_d }, 490 { gen_helper_vlxbu_v_b, gen_helper_vlxbu_v_h, 491 gen_helper_vlxbu_v_w, gen_helper_vlxbu_v_d }, 492 { NULL, gen_helper_vlxhu_v_h, 493 gen_helper_vlxhu_v_w, gen_helper_vlxhu_v_d }, 494 { NULL, NULL, 495 gen_helper_vlxwu_v_w, gen_helper_vlxwu_v_d }, 496 }; 497 498 fn = fns[seq][s->sew]; 499 if (fn == NULL) { 500 return false; 501 } 502 503 data = FIELD_DP32(data, VDATA, VM, a->vm); 504 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 505 data = FIELD_DP32(data, VDATA, NF, a->nf); 506 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 507} 508 509/* 510 * For vector indexed segment loads, the destination vector register 511 * groups cannot overlap the source vector register group (specified by 512 * `vs2`), else an illegal instruction exception is raised. 513 */ 514static bool ld_index_check(DisasContext *s, arg_rnfvm* a) 515{ 516 return (vext_check_isa_ill(s) && 517 vext_check_overlap_mask(s, a->rd, a->vm, false) && 518 vext_check_reg(s, a->rd, false) && 519 vext_check_reg(s, a->rs2, false) && 520 vext_check_nf(s, a->nf) && 521 ((a->nf == 1) || 522 vext_check_overlap_group(a->rd, a->nf << s->lmul, 523 a->rs2, 1 << s->lmul))); 524} 525 526GEN_VEXT_TRANS(vlxb_v, 0, rnfvm, ld_index_op, ld_index_check) 527GEN_VEXT_TRANS(vlxh_v, 1, rnfvm, ld_index_op, ld_index_check) 528GEN_VEXT_TRANS(vlxw_v, 2, rnfvm, ld_index_op, ld_index_check) 529GEN_VEXT_TRANS(vlxe_v, 3, rnfvm, ld_index_op, ld_index_check) 530GEN_VEXT_TRANS(vlxbu_v, 4, rnfvm, ld_index_op, ld_index_check) 531GEN_VEXT_TRANS(vlxhu_v, 5, rnfvm, ld_index_op, ld_index_check) 532GEN_VEXT_TRANS(vlxwu_v, 6, rnfvm, ld_index_op, ld_index_check) 533 534static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t seq) 535{ 536 uint32_t data = 0; 537 gen_helper_ldst_index *fn; 538 static gen_helper_ldst_index * const fns[4][4] = { 539 { gen_helper_vsxb_v_b, gen_helper_vsxb_v_h, 540 gen_helper_vsxb_v_w, gen_helper_vsxb_v_d }, 541 { NULL, gen_helper_vsxh_v_h, 542 gen_helper_vsxh_v_w, gen_helper_vsxh_v_d }, 543 { NULL, NULL, 544 gen_helper_vsxw_v_w, gen_helper_vsxw_v_d }, 545 { gen_helper_vsxe_v_b, gen_helper_vsxe_v_h, 546 gen_helper_vsxe_v_w, gen_helper_vsxe_v_d } 547 }; 548 549 fn = fns[seq][s->sew]; 550 if (fn == NULL) { 551 return false; 552 } 553 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, true); 558} 559 560static bool st_index_check(DisasContext *s, arg_rnfvm* a) 561{ 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)); 566} 567 568GEN_VEXT_TRANS(vsxb_v, 0, rnfvm, st_index_op, st_index_check) 569GEN_VEXT_TRANS(vsxh_v, 1, rnfvm, st_index_op, st_index_check) 570GEN_VEXT_TRANS(vsxw_v, 2, rnfvm, st_index_op, st_index_check) 571GEN_VEXT_TRANS(vsxe_v, 3, rnfvm, st_index_op, st_index_check) 572 573/* 574 *** unit stride fault-only-first load 575 */ 576static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, 577 gen_helper_ldst_us *fn, DisasContext *s) 578{ 579 TCGv_ptr dest, mask; 580 TCGv base; 581 TCGv_i32 desc; 582 583 TCGLabel *over = gen_new_label(); 584 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 585 586 dest = tcg_temp_new_ptr(); 587 mask = tcg_temp_new_ptr(); 588 base = get_gpr(s, rs1, EXT_NONE); 589 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 590 591 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 592 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 593 594 fn(dest, mask, base, cpu_env, desc); 595 596 tcg_temp_free_ptr(dest); 597 tcg_temp_free_ptr(mask); 598 mark_vs_dirty(s); 599 gen_set_label(over); 600 return true; 601} 602 603static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) 604{ 605 uint32_t data = 0; 606 gen_helper_ldst_us *fn; 607 static gen_helper_ldst_us * const fns[7][4] = { 608 { gen_helper_vlbff_v_b, gen_helper_vlbff_v_h, 609 gen_helper_vlbff_v_w, gen_helper_vlbff_v_d }, 610 { NULL, gen_helper_vlhff_v_h, 611 gen_helper_vlhff_v_w, gen_helper_vlhff_v_d }, 612 { NULL, NULL, 613 gen_helper_vlwff_v_w, gen_helper_vlwff_v_d }, 614 { gen_helper_vleff_v_b, gen_helper_vleff_v_h, 615 gen_helper_vleff_v_w, gen_helper_vleff_v_d }, 616 { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h, 617 gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d }, 618 { NULL, gen_helper_vlhuff_v_h, 619 gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d }, 620 { NULL, NULL, 621 gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d } 622 }; 623 624 fn = fns[seq][s->sew]; 625 if (fn == NULL) { 626 return false; 627 } 628 629 data = FIELD_DP32(data, VDATA, VM, a->vm); 630 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 631 data = FIELD_DP32(data, VDATA, NF, a->nf); 632 return ldff_trans(a->rd, a->rs1, data, fn, s); 633} 634 635GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check) 636GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check) 637GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check) 638GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check) 639GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check) 640GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check) 641GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check) 642 643/* 644 *** vector atomic operation 645 */ 646typedef void gen_helper_amo(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 647 TCGv_env, TCGv_i32); 648 649static bool amo_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 650 uint32_t data, gen_helper_amo *fn, DisasContext *s) 651{ 652 TCGv_ptr dest, mask, index; 653 TCGv base; 654 TCGv_i32 desc; 655 656 TCGLabel *over = gen_new_label(); 657 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 658 659 dest = tcg_temp_new_ptr(); 660 mask = tcg_temp_new_ptr(); 661 index = tcg_temp_new_ptr(); 662 base = get_gpr(s, rs1, EXT_NONE); 663 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 664 665 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 666 tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); 667 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 668 669 fn(dest, mask, base, index, cpu_env, desc); 670 671 tcg_temp_free_ptr(dest); 672 tcg_temp_free_ptr(mask); 673 tcg_temp_free_ptr(index); 674 mark_vs_dirty(s); 675 gen_set_label(over); 676 return true; 677} 678 679static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) 680{ 681 uint32_t data = 0; 682 gen_helper_amo *fn; 683 static gen_helper_amo *const fnsw[9] = { 684 /* no atomic operation */ 685 gen_helper_vamoswapw_v_w, 686 gen_helper_vamoaddw_v_w, 687 gen_helper_vamoxorw_v_w, 688 gen_helper_vamoandw_v_w, 689 gen_helper_vamoorw_v_w, 690 gen_helper_vamominw_v_w, 691 gen_helper_vamomaxw_v_w, 692 gen_helper_vamominuw_v_w, 693 gen_helper_vamomaxuw_v_w 694 }; 695 static gen_helper_amo *const fnsd[18] = { 696 gen_helper_vamoswapw_v_d, 697 gen_helper_vamoaddw_v_d, 698 gen_helper_vamoxorw_v_d, 699 gen_helper_vamoandw_v_d, 700 gen_helper_vamoorw_v_d, 701 gen_helper_vamominw_v_d, 702 gen_helper_vamomaxw_v_d, 703 gen_helper_vamominuw_v_d, 704 gen_helper_vamomaxuw_v_d, 705 gen_helper_vamoswapd_v_d, 706 gen_helper_vamoaddd_v_d, 707 gen_helper_vamoxord_v_d, 708 gen_helper_vamoandd_v_d, 709 gen_helper_vamoord_v_d, 710 gen_helper_vamomind_v_d, 711 gen_helper_vamomaxd_v_d, 712 gen_helper_vamominud_v_d, 713 gen_helper_vamomaxud_v_d 714 }; 715 716 if (tb_cflags(s->base.tb) & CF_PARALLEL) { 717 gen_helper_exit_atomic(cpu_env); 718 s->base.is_jmp = DISAS_NORETURN; 719 return true; 720 } 721 722 switch (s->sew) { 723 case 0 ... 2: 724 assert(seq < ARRAY_SIZE(fnsw)); 725 fn = fnsw[seq]; 726 break; 727 case 3: 728 /* XLEN check done in amo_check(). */ 729 assert(seq < ARRAY_SIZE(fnsd)); 730 fn = fnsd[seq]; 731 break; 732 default: 733 g_assert_not_reached(); 734 } 735 736 data = FIELD_DP32(data, VDATA, VM, a->vm); 737 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 738 data = FIELD_DP32(data, VDATA, WD, a->wd); 739 return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s); 740} 741/* 742 * There are two rules check here. 743 * 744 * 1. SEW must be at least as wide as the AMO memory element size. 745 * 746 * 2. If SEW is greater than XLEN, an illegal instruction exception is raised. 747 */ 748static bool amo_check(DisasContext *s, arg_rwdvm* a) 749{ 750 return (!s->vill && has_ext(s, RVA) && 751 (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) && 752 vext_check_reg(s, a->rd, false) && 753 vext_check_reg(s, a->rs2, false) && 754 ((1 << s->sew) <= sizeof(target_ulong)) && 755 ((1 << s->sew) >= 4)); 756} 757 758static bool amo_check64(DisasContext *s, arg_rwdvm* a) 759{ 760 REQUIRE_64BIT(s); 761 return amo_check(s, a); 762} 763 764GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) 765GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check) 766GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check) 767GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check) 768GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check) 769GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check) 770GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check) 771GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check) 772GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check) 773GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64) 774GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64) 775GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64) 776GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64) 777GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64) 778GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64) 779GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64) 780GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64) 781GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64) 782 783/* 784 *** Vector Integer Arithmetic Instructions 785 */ 786#define MAXSZ(s) (s->vlen >> (3 - s->lmul)) 787 788static bool opivv_check(DisasContext *s, arg_rmrr *a) 789{ 790 return (vext_check_isa_ill(s) && 791 vext_check_overlap_mask(s, a->rd, a->vm, false) && 792 vext_check_reg(s, a->rd, false) && 793 vext_check_reg(s, a->rs2, false) && 794 vext_check_reg(s, a->rs1, false)); 795} 796 797typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 798 uint32_t, uint32_t, uint32_t); 799 800static inline bool 801do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 802 gen_helper_gvec_4_ptr *fn) 803{ 804 TCGLabel *over = gen_new_label(); 805 if (!opivv_check(s, a)) { 806 return false; 807 } 808 809 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 810 811 if (a->vm && s->vl_eq_vlmax) { 812 gvec_fn(s->sew, vreg_ofs(s, a->rd), 813 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 814 MAXSZ(s), MAXSZ(s)); 815 } else { 816 uint32_t data = 0; 817 818 data = FIELD_DP32(data, VDATA, VM, a->vm); 819 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 820 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 821 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 822 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 823 } 824 mark_vs_dirty(s); 825 gen_set_label(over); 826 return true; 827} 828 829/* OPIVV with GVEC IR */ 830#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 831static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 832{ \ 833 static gen_helper_gvec_4_ptr * const fns[4] = { \ 834 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 835 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 836 }; \ 837 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 838} 839 840GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 841GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 842 843typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 844 TCGv_env, TCGv_i32); 845 846static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 847 gen_helper_opivx *fn, DisasContext *s) 848{ 849 TCGv_ptr dest, src2, mask; 850 TCGv src1; 851 TCGv_i32 desc; 852 uint32_t data = 0; 853 854 TCGLabel *over = gen_new_label(); 855 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 856 857 dest = tcg_temp_new_ptr(); 858 mask = tcg_temp_new_ptr(); 859 src2 = tcg_temp_new_ptr(); 860 src1 = get_gpr(s, rs1, EXT_NONE); 861 862 data = FIELD_DP32(data, VDATA, VM, vm); 863 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 864 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 865 866 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 867 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 868 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 869 870 fn(dest, mask, src1, src2, cpu_env, desc); 871 872 tcg_temp_free_ptr(dest); 873 tcg_temp_free_ptr(mask); 874 tcg_temp_free_ptr(src2); 875 mark_vs_dirty(s); 876 gen_set_label(over); 877 return true; 878} 879 880static bool opivx_check(DisasContext *s, arg_rmrr *a) 881{ 882 return (vext_check_isa_ill(s) && 883 vext_check_overlap_mask(s, a->rd, a->vm, false) && 884 vext_check_reg(s, a->rd, false) && 885 vext_check_reg(s, a->rs2, false)); 886} 887 888typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 889 uint32_t, uint32_t); 890 891static inline bool 892do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 893 gen_helper_opivx *fn) 894{ 895 if (!opivx_check(s, a)) { 896 return false; 897 } 898 899 if (a->vm && s->vl_eq_vlmax) { 900 TCGv_i64 src1 = tcg_temp_new_i64(); 901 902 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 903 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 904 src1, MAXSZ(s), MAXSZ(s)); 905 906 tcg_temp_free_i64(src1); 907 mark_vs_dirty(s); 908 return true; 909 } 910 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 911} 912 913/* OPIVX with GVEC IR */ 914#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 915static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 916{ \ 917 static gen_helper_opivx * const fns[4] = { \ 918 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 919 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 920 }; \ 921 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 922} 923 924GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 925GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 926 927static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 928{ 929 tcg_gen_vec_sub8_i64(d, b, a); 930} 931 932static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 933{ 934 tcg_gen_vec_sub16_i64(d, b, a); 935} 936 937static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 938{ 939 tcg_gen_sub_i32(ret, arg2, arg1); 940} 941 942static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 943{ 944 tcg_gen_sub_i64(ret, arg2, arg1); 945} 946 947static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 948{ 949 tcg_gen_sub_vec(vece, r, b, a); 950} 951 952static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 953 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 954{ 955 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 956 static const GVecGen2s rsub_op[4] = { 957 { .fni8 = gen_vec_rsub8_i64, 958 .fniv = gen_rsub_vec, 959 .fno = gen_helper_vec_rsubs8, 960 .opt_opc = vecop_list, 961 .vece = MO_8 }, 962 { .fni8 = gen_vec_rsub16_i64, 963 .fniv = gen_rsub_vec, 964 .fno = gen_helper_vec_rsubs16, 965 .opt_opc = vecop_list, 966 .vece = MO_16 }, 967 { .fni4 = gen_rsub_i32, 968 .fniv = gen_rsub_vec, 969 .fno = gen_helper_vec_rsubs32, 970 .opt_opc = vecop_list, 971 .vece = MO_32 }, 972 { .fni8 = gen_rsub_i64, 973 .fniv = gen_rsub_vec, 974 .fno = gen_helper_vec_rsubs64, 975 .opt_opc = vecop_list, 976 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 977 .vece = MO_64 }, 978 }; 979 980 tcg_debug_assert(vece <= MO_64); 981 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 982} 983 984GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 985 986static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 987 gen_helper_opivx *fn, DisasContext *s, int zx) 988{ 989 TCGv_ptr dest, src2, mask; 990 TCGv src1; 991 TCGv_i32 desc; 992 uint32_t data = 0; 993 994 TCGLabel *over = gen_new_label(); 995 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 996 997 dest = tcg_temp_new_ptr(); 998 mask = tcg_temp_new_ptr(); 999 src2 = tcg_temp_new_ptr(); 1000 if (zx) { 1001 src1 = tcg_constant_tl(imm); 1002 } else { 1003 src1 = tcg_constant_tl(sextract64(imm, 0, 5)); 1004 } 1005 data = FIELD_DP32(data, VDATA, VM, vm); 1006 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1007 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1008 1009 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1010 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1011 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1012 1013 fn(dest, mask, src1, src2, cpu_env, desc); 1014 1015 tcg_temp_free_ptr(dest); 1016 tcg_temp_free_ptr(mask); 1017 tcg_temp_free_ptr(src2); 1018 mark_vs_dirty(s); 1019 gen_set_label(over); 1020 return true; 1021} 1022 1023typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1024 uint32_t, uint32_t); 1025 1026static inline bool 1027do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1028 gen_helper_opivx *fn, int zx) 1029{ 1030 if (!opivx_check(s, a)) { 1031 return false; 1032 } 1033 1034 if (a->vm && s->vl_eq_vlmax) { 1035 if (zx) { 1036 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1037 extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); 1038 } else { 1039 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1040 sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); 1041 } 1042 mark_vs_dirty(s); 1043 return true; 1044 } 1045 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx); 1046} 1047 1048/* OPIVI with GVEC IR */ 1049#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \ 1050static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1051{ \ 1052 static gen_helper_opivx * const fns[4] = { \ 1053 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1054 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1055 }; \ 1056 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1057 fns[s->sew], ZX); \ 1058} 1059 1060GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi) 1061 1062static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1063 int64_t c, uint32_t oprsz, uint32_t maxsz) 1064{ 1065 TCGv_i64 tmp = tcg_constant_i64(c); 1066 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1067} 1068 1069GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi) 1070 1071/* Vector Widening Integer Add/Subtract */ 1072 1073/* OPIVV with WIDEN */ 1074static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1075{ 1076 return (vext_check_isa_ill(s) && 1077 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1078 vext_check_reg(s, a->rd, true) && 1079 vext_check_reg(s, a->rs2, false) && 1080 vext_check_reg(s, a->rs1, false) && 1081 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1082 1 << s->lmul) && 1083 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1084 1 << s->lmul) && 1085 (s->lmul < 0x3) && (s->sew < 0x3)); 1086} 1087 1088static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1089 gen_helper_gvec_4_ptr *fn, 1090 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1091{ 1092 if (checkfn(s, a)) { 1093 uint32_t data = 0; 1094 TCGLabel *over = gen_new_label(); 1095 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1096 1097 data = FIELD_DP32(data, VDATA, VM, a->vm); 1098 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1099 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1100 vreg_ofs(s, a->rs1), 1101 vreg_ofs(s, a->rs2), 1102 cpu_env, s->vlen / 8, s->vlen / 8, 1103 data, fn); 1104 mark_vs_dirty(s); 1105 gen_set_label(over); 1106 return true; 1107 } 1108 return false; 1109} 1110 1111#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1112static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1113{ \ 1114 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1115 gen_helper_##NAME##_b, \ 1116 gen_helper_##NAME##_h, \ 1117 gen_helper_##NAME##_w \ 1118 }; \ 1119 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1120} 1121 1122GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1123GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1124GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1125GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1126 1127/* OPIVX with WIDEN */ 1128static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1129{ 1130 return (vext_check_isa_ill(s) && 1131 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1132 vext_check_reg(s, a->rd, true) && 1133 vext_check_reg(s, a->rs2, false) && 1134 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1135 1 << s->lmul) && 1136 (s->lmul < 0x3) && (s->sew < 0x3)); 1137} 1138 1139static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, 1140 gen_helper_opivx *fn) 1141{ 1142 if (opivx_widen_check(s, a)) { 1143 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1144 } 1145 return false; 1146} 1147 1148#define GEN_OPIVX_WIDEN_TRANS(NAME) \ 1149static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1150{ \ 1151 static gen_helper_opivx * const fns[3] = { \ 1152 gen_helper_##NAME##_b, \ 1153 gen_helper_##NAME##_h, \ 1154 gen_helper_##NAME##_w \ 1155 }; \ 1156 return do_opivx_widen(s, a, fns[s->sew]); \ 1157} 1158 1159GEN_OPIVX_WIDEN_TRANS(vwaddu_vx) 1160GEN_OPIVX_WIDEN_TRANS(vwadd_vx) 1161GEN_OPIVX_WIDEN_TRANS(vwsubu_vx) 1162GEN_OPIVX_WIDEN_TRANS(vwsub_vx) 1163 1164/* WIDEN OPIVV with WIDEN */ 1165static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1166{ 1167 return (vext_check_isa_ill(s) && 1168 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1169 vext_check_reg(s, a->rd, true) && 1170 vext_check_reg(s, a->rs2, true) && 1171 vext_check_reg(s, a->rs1, false) && 1172 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1173 1 << s->lmul) && 1174 (s->lmul < 0x3) && (s->sew < 0x3)); 1175} 1176 1177static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1178 gen_helper_gvec_4_ptr *fn) 1179{ 1180 if (opiwv_widen_check(s, a)) { 1181 uint32_t data = 0; 1182 TCGLabel *over = gen_new_label(); 1183 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1184 1185 data = FIELD_DP32(data, VDATA, VM, a->vm); 1186 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1187 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1188 vreg_ofs(s, a->rs1), 1189 vreg_ofs(s, a->rs2), 1190 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1191 mark_vs_dirty(s); 1192 gen_set_label(over); 1193 return true; 1194 } 1195 return false; 1196} 1197 1198#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1199static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1200{ \ 1201 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1202 gen_helper_##NAME##_b, \ 1203 gen_helper_##NAME##_h, \ 1204 gen_helper_##NAME##_w \ 1205 }; \ 1206 return do_opiwv_widen(s, a, fns[s->sew]); \ 1207} 1208 1209GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1210GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1211GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1212GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1213 1214/* WIDEN OPIVX with WIDEN */ 1215static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1216{ 1217 return (vext_check_isa_ill(s) && 1218 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1219 vext_check_reg(s, a->rd, true) && 1220 vext_check_reg(s, a->rs2, true) && 1221 (s->lmul < 0x3) && (s->sew < 0x3)); 1222} 1223 1224static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1225 gen_helper_opivx *fn) 1226{ 1227 if (opiwx_widen_check(s, a)) { 1228 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1229 } 1230 return false; 1231} 1232 1233#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1234static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1235{ \ 1236 static gen_helper_opivx * const fns[3] = { \ 1237 gen_helper_##NAME##_b, \ 1238 gen_helper_##NAME##_h, \ 1239 gen_helper_##NAME##_w \ 1240 }; \ 1241 return do_opiwx_widen(s, a, fns[s->sew]); \ 1242} 1243 1244GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1245GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1246GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1247GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1248 1249/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1250/* OPIVV without GVEC IR */ 1251#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1252static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1253{ \ 1254 if (CHECK(s, a)) { \ 1255 uint32_t data = 0; \ 1256 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1257 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1258 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1259 }; \ 1260 TCGLabel *over = gen_new_label(); \ 1261 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1262 \ 1263 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1264 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1265 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1266 vreg_ofs(s, a->rs1), \ 1267 vreg_ofs(s, a->rs2), cpu_env, \ 1268 s->vlen / 8, s->vlen / 8, data, \ 1269 fns[s->sew]); \ 1270 mark_vs_dirty(s); \ 1271 gen_set_label(over); \ 1272 return true; \ 1273 } \ 1274 return false; \ 1275} 1276 1277/* 1278 * For vadc and vsbc, an illegal instruction exception is raised if the 1279 * destination vector register is v0 and LMUL > 1. (Section 12.3) 1280 */ 1281static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1282{ 1283 return (vext_check_isa_ill(s) && 1284 vext_check_reg(s, a->rd, false) && 1285 vext_check_reg(s, a->rs2, false) && 1286 vext_check_reg(s, a->rs1, false) && 1287 ((a->rd != 0) || (s->lmul == 0))); 1288} 1289 1290GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1291GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1292 1293/* 1294 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1295 * destination vector register overlaps a source vector register group. 1296 */ 1297static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1298{ 1299 return (vext_check_isa_ill(s) && 1300 vext_check_reg(s, a->rs2, false) && 1301 vext_check_reg(s, a->rs1, false) && 1302 vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1303 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1304} 1305 1306GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1307GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1308 1309static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1310{ 1311 return (vext_check_isa_ill(s) && 1312 vext_check_reg(s, a->rd, false) && 1313 vext_check_reg(s, a->rs2, false) && 1314 ((a->rd != 0) || (s->lmul == 0))); 1315} 1316 1317/* OPIVX without GVEC IR */ 1318#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1319static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1320{ \ 1321 if (CHECK(s, a)) { \ 1322 static gen_helper_opivx * const fns[4] = { \ 1323 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1324 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1325 }; \ 1326 \ 1327 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1328 } \ 1329 return false; \ 1330} 1331 1332GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1333GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1334 1335static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1336{ 1337 return (vext_check_isa_ill(s) && 1338 vext_check_reg(s, a->rs2, false) && 1339 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1340} 1341 1342GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1343GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1344 1345/* OPIVI without GVEC IR */ 1346#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \ 1347static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1348{ \ 1349 if (CHECK(s, a)) { \ 1350 static gen_helper_opivx * const fns[4] = { \ 1351 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1352 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1353 }; \ 1354 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1355 fns[s->sew], s, ZX); \ 1356 } \ 1357 return false; \ 1358} 1359 1360GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check) 1361GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check) 1362 1363/* Vector Bitwise Logical Instructions */ 1364GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1365GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1366GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1367GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1368GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1369GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1370GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi) 1371GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori) 1372GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori) 1373 1374/* Vector Single-Width Bit Shift Instructions */ 1375GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1376GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1377GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1378 1379typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1380 uint32_t, uint32_t); 1381 1382static inline bool 1383do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1384 gen_helper_opivx *fn) 1385{ 1386 if (!opivx_check(s, a)) { 1387 return false; 1388 } 1389 1390 if (a->vm && s->vl_eq_vlmax) { 1391 TCGv_i32 src1 = tcg_temp_new_i32(); 1392 1393 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1394 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1395 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1396 src1, MAXSZ(s), MAXSZ(s)); 1397 1398 tcg_temp_free_i32(src1); 1399 mark_vs_dirty(s); 1400 return true; 1401 } 1402 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1403} 1404 1405#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1406static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1407{ \ 1408 static gen_helper_opivx * const fns[4] = { \ 1409 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1410 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1411 }; \ 1412 \ 1413 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1414} 1415 1416GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1417GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1418GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1419 1420GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli) 1421GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri) 1422GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari) 1423 1424/* Vector Narrowing Integer Right Shift Instructions */ 1425static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) 1426{ 1427 return (vext_check_isa_ill(s) && 1428 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1429 vext_check_reg(s, a->rd, false) && 1430 vext_check_reg(s, a->rs2, true) && 1431 vext_check_reg(s, a->rs1, false) && 1432 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1433 2 << s->lmul) && 1434 (s->lmul < 0x3) && (s->sew < 0x3)); 1435} 1436 1437/* OPIVV with NARROW */ 1438#define GEN_OPIVV_NARROW_TRANS(NAME) \ 1439static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1440{ \ 1441 if (opivv_narrow_check(s, a)) { \ 1442 uint32_t data = 0; \ 1443 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1444 gen_helper_##NAME##_b, \ 1445 gen_helper_##NAME##_h, \ 1446 gen_helper_##NAME##_w, \ 1447 }; \ 1448 TCGLabel *over = gen_new_label(); \ 1449 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1450 \ 1451 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1452 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1453 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1454 vreg_ofs(s, a->rs1), \ 1455 vreg_ofs(s, a->rs2), cpu_env, \ 1456 s->vlen / 8, s->vlen / 8, data, \ 1457 fns[s->sew]); \ 1458 mark_vs_dirty(s); \ 1459 gen_set_label(over); \ 1460 return true; \ 1461 } \ 1462 return false; \ 1463} 1464GEN_OPIVV_NARROW_TRANS(vnsra_vv) 1465GEN_OPIVV_NARROW_TRANS(vnsrl_vv) 1466 1467static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) 1468{ 1469 return (vext_check_isa_ill(s) && 1470 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1471 vext_check_reg(s, a->rd, false) && 1472 vext_check_reg(s, a->rs2, true) && 1473 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1474 2 << s->lmul) && 1475 (s->lmul < 0x3) && (s->sew < 0x3)); 1476} 1477 1478/* OPIVX with NARROW */ 1479#define GEN_OPIVX_NARROW_TRANS(NAME) \ 1480static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1481{ \ 1482 if (opivx_narrow_check(s, a)) { \ 1483 static gen_helper_opivx * const fns[3] = { \ 1484 gen_helper_##NAME##_b, \ 1485 gen_helper_##NAME##_h, \ 1486 gen_helper_##NAME##_w, \ 1487 }; \ 1488 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1489 } \ 1490 return false; \ 1491} 1492 1493GEN_OPIVX_NARROW_TRANS(vnsra_vx) 1494GEN_OPIVX_NARROW_TRANS(vnsrl_vx) 1495 1496/* OPIVI with NARROW */ 1497#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \ 1498static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1499{ \ 1500 if (opivx_narrow_check(s, a)) { \ 1501 static gen_helper_opivx * const fns[3] = { \ 1502 gen_helper_##OPIVX##_b, \ 1503 gen_helper_##OPIVX##_h, \ 1504 gen_helper_##OPIVX##_w, \ 1505 }; \ 1506 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1507 fns[s->sew], s, ZX); \ 1508 } \ 1509 return false; \ 1510} 1511 1512GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx) 1513GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx) 1514 1515/* Vector Integer Comparison Instructions */ 1516/* 1517 * For all comparison instructions, an illegal instruction exception is raised 1518 * if the destination vector register overlaps a source vector register group 1519 * and LMUL > 1. 1520 */ 1521static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1522{ 1523 return (vext_check_isa_ill(s) && 1524 vext_check_reg(s, a->rs2, false) && 1525 vext_check_reg(s, a->rs1, false) && 1526 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1527 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 1528 (s->lmul == 0))); 1529} 1530GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1531GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1532GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1533GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1534GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1535GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1536 1537static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1538{ 1539 return (vext_check_isa_ill(s) && 1540 vext_check_reg(s, a->rs2, false) && 1541 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 1542 (s->lmul == 0))); 1543} 1544 1545GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1546GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1547GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1548GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1549GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1550GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1551GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1552GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1553 1554GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check) 1555GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check) 1556GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check) 1557GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check) 1558GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check) 1559GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check) 1560 1561/* Vector Integer Min/Max Instructions */ 1562GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1563GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1564GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1565GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1566GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1567GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1568GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1569GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1570 1571/* Vector Single-Width Integer Multiply Instructions */ 1572GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1573GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1574GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1575GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1576GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1577GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1578GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1579GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1580 1581/* Vector Integer Divide Instructions */ 1582GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1583GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1584GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1585GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1586GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1587GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1588GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1589GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1590 1591/* Vector Widening Integer Multiply Instructions */ 1592GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1593GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1594GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1595GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1596GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1597GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1598 1599/* Vector Single-Width Integer Multiply-Add Instructions */ 1600GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1601GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1602GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1603GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1604GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1605GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1606GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1607GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1608 1609/* Vector Widening Integer Multiply-Add Instructions */ 1610GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1611GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1612GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1613GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1614GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1615GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1616GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1617 1618/* Vector Integer Merge and Move Instructions */ 1619static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1620{ 1621 if (vext_check_isa_ill(s) && 1622 vext_check_reg(s, a->rd, false) && 1623 vext_check_reg(s, a->rs1, false)) { 1624 1625 if (s->vl_eq_vlmax) { 1626 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1627 vreg_ofs(s, a->rs1), 1628 MAXSZ(s), MAXSZ(s)); 1629 } else { 1630 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1631 static gen_helper_gvec_2_ptr * const fns[4] = { 1632 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1633 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1634 }; 1635 TCGLabel *over = gen_new_label(); 1636 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1637 1638 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1639 cpu_env, s->vlen / 8, s->vlen / 8, data, 1640 fns[s->sew]); 1641 gen_set_label(over); 1642 } 1643 mark_vs_dirty(s); 1644 return true; 1645 } 1646 return false; 1647} 1648 1649typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1650static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1651{ 1652 if (vext_check_isa_ill(s) && 1653 vext_check_reg(s, a->rd, false)) { 1654 1655 TCGv s1; 1656 TCGLabel *over = gen_new_label(); 1657 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1658 1659 s1 = get_gpr(s, a->rs1, EXT_SIGN); 1660 1661 if (s->vl_eq_vlmax) { 1662 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 1663 MAXSZ(s), MAXSZ(s), s1); 1664 } else { 1665 TCGv_i32 desc; 1666 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 1667 TCGv_ptr dest = tcg_temp_new_ptr(); 1668 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1669 static gen_helper_vmv_vx * const fns[4] = { 1670 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1671 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1672 }; 1673 1674 tcg_gen_ext_tl_i64(s1_i64, s1); 1675 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1676 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1677 fns[s->sew](dest, s1_i64, cpu_env, desc); 1678 1679 tcg_temp_free_ptr(dest); 1680 tcg_temp_free_i64(s1_i64); 1681 } 1682 1683 mark_vs_dirty(s); 1684 gen_set_label(over); 1685 return true; 1686 } 1687 return false; 1688} 1689 1690static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 1691{ 1692 if (vext_check_isa_ill(s) && 1693 vext_check_reg(s, a->rd, false)) { 1694 1695 int64_t simm = sextract64(a->rs1, 0, 5); 1696 if (s->vl_eq_vlmax) { 1697 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 1698 MAXSZ(s), MAXSZ(s), simm); 1699 mark_vs_dirty(s); 1700 } else { 1701 TCGv_i32 desc; 1702 TCGv_i64 s1; 1703 TCGv_ptr dest; 1704 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1705 static gen_helper_vmv_vx * const fns[4] = { 1706 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1707 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1708 }; 1709 TCGLabel *over = gen_new_label(); 1710 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1711 1712 s1 = tcg_constant_i64(simm); 1713 dest = tcg_temp_new_ptr(); 1714 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1715 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1716 fns[s->sew](dest, s1, cpu_env, desc); 1717 1718 tcg_temp_free_ptr(dest); 1719 mark_vs_dirty(s); 1720 gen_set_label(over); 1721 } 1722 return true; 1723 } 1724 return false; 1725} 1726 1727GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 1728GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 1729GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check) 1730 1731/* 1732 *** Vector Fixed-Point Arithmetic Instructions 1733 */ 1734 1735/* Vector Single-Width Saturating Add and Subtract */ 1736GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 1737GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 1738GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 1739GEN_OPIVV_TRANS(vssub_vv, opivv_check) 1740GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 1741GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 1742GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 1743GEN_OPIVX_TRANS(vssub_vx, opivx_check) 1744GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check) 1745GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check) 1746 1747/* Vector Single-Width Averaging Add and Subtract */ 1748GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 1749GEN_OPIVV_TRANS(vasub_vv, opivv_check) 1750GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 1751GEN_OPIVX_TRANS(vasub_vx, opivx_check) 1752GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) 1753 1754/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 1755GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 1756GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 1757 1758/* Vector Widening Saturating Scaled Multiply-Add */ 1759GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) 1760GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) 1761GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) 1762GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) 1763GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) 1764GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) 1765GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) 1766 1767/* Vector Single-Width Scaling Shift Instructions */ 1768GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 1769GEN_OPIVV_TRANS(vssra_vv, opivv_check) 1770GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 1771GEN_OPIVX_TRANS(vssra_vx, opivx_check) 1772GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check) 1773GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check) 1774 1775/* Vector Narrowing Fixed-Point Clip Instructions */ 1776GEN_OPIVV_NARROW_TRANS(vnclipu_vv) 1777GEN_OPIVV_NARROW_TRANS(vnclip_vv) 1778GEN_OPIVX_NARROW_TRANS(vnclipu_vx) 1779GEN_OPIVX_NARROW_TRANS(vnclip_vx) 1780GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx) 1781GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx) 1782 1783/* 1784 *** Vector Float Point Arithmetic Instructions 1785 */ 1786/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 1787 1788/* 1789 * If the current SEW does not correspond to a supported IEEE floating-point 1790 * type, an illegal instruction exception is raised. 1791 */ 1792static bool opfvv_check(DisasContext *s, arg_rmrr *a) 1793{ 1794 return (vext_check_isa_ill(s) && 1795 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1796 vext_check_reg(s, a->rd, false) && 1797 vext_check_reg(s, a->rs2, false) && 1798 vext_check_reg(s, a->rs1, false) && 1799 (s->sew != 0)); 1800} 1801 1802/* OPFVV without GVEC IR */ 1803#define GEN_OPFVV_TRANS(NAME, CHECK) \ 1804static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1805{ \ 1806 if (CHECK(s, a)) { \ 1807 uint32_t data = 0; \ 1808 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1809 gen_helper_##NAME##_h, \ 1810 gen_helper_##NAME##_w, \ 1811 gen_helper_##NAME##_d, \ 1812 }; \ 1813 TCGLabel *over = gen_new_label(); \ 1814 gen_set_rm(s, 7); \ 1815 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1816 \ 1817 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1818 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1819 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1820 vreg_ofs(s, a->rs1), \ 1821 vreg_ofs(s, a->rs2), cpu_env, \ 1822 s->vlen / 8, s->vlen / 8, data, \ 1823 fns[s->sew - 1]); \ 1824 mark_vs_dirty(s); \ 1825 gen_set_label(over); \ 1826 return true; \ 1827 } \ 1828 return false; \ 1829} 1830GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 1831GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 1832 1833typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 1834 TCGv_env, TCGv_i32); 1835 1836static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 1837 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 1838{ 1839 TCGv_ptr dest, src2, mask; 1840 TCGv_i32 desc; 1841 1842 TCGLabel *over = gen_new_label(); 1843 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1844 1845 dest = tcg_temp_new_ptr(); 1846 mask = tcg_temp_new_ptr(); 1847 src2 = tcg_temp_new_ptr(); 1848 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1849 1850 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1851 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1852 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1853 1854 fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc); 1855 1856 tcg_temp_free_ptr(dest); 1857 tcg_temp_free_ptr(mask); 1858 tcg_temp_free_ptr(src2); 1859 mark_vs_dirty(s); 1860 gen_set_label(over); 1861 return true; 1862} 1863 1864static bool opfvf_check(DisasContext *s, arg_rmrr *a) 1865{ 1866/* 1867 * If the current SEW does not correspond to a supported IEEE floating-point 1868 * type, an illegal instruction exception is raised 1869 */ 1870 return (vext_check_isa_ill(s) && 1871 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1872 vext_check_reg(s, a->rd, false) && 1873 vext_check_reg(s, a->rs2, false) && 1874 (s->sew != 0)); 1875} 1876 1877/* OPFVF without GVEC IR */ 1878#define GEN_OPFVF_TRANS(NAME, CHECK) \ 1879static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1880{ \ 1881 if (CHECK(s, a)) { \ 1882 uint32_t data = 0; \ 1883 static gen_helper_opfvf *const fns[3] = { \ 1884 gen_helper_##NAME##_h, \ 1885 gen_helper_##NAME##_w, \ 1886 gen_helper_##NAME##_d, \ 1887 }; \ 1888 gen_set_rm(s, 7); \ 1889 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1890 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1891 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1892 fns[s->sew - 1], s); \ 1893 } \ 1894 return false; \ 1895} 1896 1897GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 1898GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 1899GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 1900 1901/* Vector Widening Floating-Point Add/Subtract Instructions */ 1902static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 1903{ 1904 return (vext_check_isa_ill(s) && 1905 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1906 vext_check_reg(s, a->rd, true) && 1907 vext_check_reg(s, a->rs2, false) && 1908 vext_check_reg(s, a->rs1, false) && 1909 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1910 1 << s->lmul) && 1911 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1912 1 << s->lmul) && 1913 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1914} 1915 1916/* OPFVV with WIDEN */ 1917#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 1918static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1919{ \ 1920 if (CHECK(s, a)) { \ 1921 uint32_t data = 0; \ 1922 static gen_helper_gvec_4_ptr * const fns[2] = { \ 1923 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1924 }; \ 1925 TCGLabel *over = gen_new_label(); \ 1926 gen_set_rm(s, 7); \ 1927 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1928 \ 1929 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1930 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1931 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1932 vreg_ofs(s, a->rs1), \ 1933 vreg_ofs(s, a->rs2), cpu_env, \ 1934 s->vlen / 8, s->vlen / 8, data, \ 1935 fns[s->sew - 1]); \ 1936 mark_vs_dirty(s); \ 1937 gen_set_label(over); \ 1938 return true; \ 1939 } \ 1940 return false; \ 1941} 1942 1943GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 1944GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 1945 1946static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 1947{ 1948 return (vext_check_isa_ill(s) && 1949 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1950 vext_check_reg(s, a->rd, true) && 1951 vext_check_reg(s, a->rs2, false) && 1952 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1953 1 << s->lmul) && 1954 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1955} 1956 1957/* OPFVF with WIDEN */ 1958#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 1959static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1960{ \ 1961 if (opfvf_widen_check(s, a)) { \ 1962 uint32_t data = 0; \ 1963 static gen_helper_opfvf *const fns[2] = { \ 1964 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1965 }; \ 1966 gen_set_rm(s, 7); \ 1967 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1968 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1969 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1970 fns[s->sew - 1], s); \ 1971 } \ 1972 return false; \ 1973} 1974 1975GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 1976GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 1977 1978static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 1979{ 1980 return (vext_check_isa_ill(s) && 1981 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1982 vext_check_reg(s, a->rd, true) && 1983 vext_check_reg(s, a->rs2, true) && 1984 vext_check_reg(s, a->rs1, false) && 1985 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1986 1 << s->lmul) && 1987 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1988} 1989 1990/* WIDEN OPFVV with WIDEN */ 1991#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 1992static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1993{ \ 1994 if (opfwv_widen_check(s, a)) { \ 1995 uint32_t data = 0; \ 1996 static gen_helper_gvec_4_ptr * const fns[2] = { \ 1997 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1998 }; \ 1999 TCGLabel *over = gen_new_label(); \ 2000 gen_set_rm(s, 7); \ 2001 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2002 \ 2003 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2004 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2005 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2006 vreg_ofs(s, a->rs1), \ 2007 vreg_ofs(s, a->rs2), cpu_env, \ 2008 s->vlen / 8, s->vlen / 8, data, \ 2009 fns[s->sew - 1]); \ 2010 mark_vs_dirty(s); \ 2011 gen_set_label(over); \ 2012 return true; \ 2013 } \ 2014 return false; \ 2015} 2016 2017GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2018GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2019 2020static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2021{ 2022 return (vext_check_isa_ill(s) && 2023 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2024 vext_check_reg(s, a->rd, true) && 2025 vext_check_reg(s, a->rs2, true) && 2026 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2027} 2028 2029/* WIDEN OPFVF with WIDEN */ 2030#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2031static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2032{ \ 2033 if (opfwf_widen_check(s, a)) { \ 2034 uint32_t data = 0; \ 2035 static gen_helper_opfvf *const fns[2] = { \ 2036 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2037 }; \ 2038 gen_set_rm(s, 7); \ 2039 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2040 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2041 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2042 fns[s->sew - 1], s); \ 2043 } \ 2044 return false; \ 2045} 2046 2047GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2048GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2049 2050/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2051GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2052GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2053GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2054GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2055GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2056 2057/* Vector Widening Floating-Point Multiply */ 2058GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2059GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2060 2061/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2062GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2063GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2064GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2065GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2066GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2067GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2068GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2069GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2070GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2071GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2072GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2073GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2074GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2075GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2076GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2077GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2078 2079/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2080GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2081GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2082GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2083GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2084GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2085GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2086GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2087GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2088 2089/* Vector Floating-Point Square-Root Instruction */ 2090 2091/* 2092 * If the current SEW does not correspond to a supported IEEE floating-point 2093 * type, an illegal instruction exception is raised 2094 */ 2095static bool opfv_check(DisasContext *s, arg_rmr *a) 2096{ 2097 return (vext_check_isa_ill(s) && 2098 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2099 vext_check_reg(s, a->rd, false) && 2100 vext_check_reg(s, a->rs2, false) && 2101 (s->sew != 0)); 2102} 2103 2104#define GEN_OPFV_TRANS(NAME, CHECK) \ 2105static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2106{ \ 2107 if (CHECK(s, a)) { \ 2108 uint32_t data = 0; \ 2109 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2110 gen_helper_##NAME##_h, \ 2111 gen_helper_##NAME##_w, \ 2112 gen_helper_##NAME##_d, \ 2113 }; \ 2114 TCGLabel *over = gen_new_label(); \ 2115 gen_set_rm(s, 7); \ 2116 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2117 \ 2118 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2119 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2120 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2121 vreg_ofs(s, a->rs2), cpu_env, \ 2122 s->vlen / 8, s->vlen / 8, data, \ 2123 fns[s->sew - 1]); \ 2124 mark_vs_dirty(s); \ 2125 gen_set_label(over); \ 2126 return true; \ 2127 } \ 2128 return false; \ 2129} 2130 2131GEN_OPFV_TRANS(vfsqrt_v, opfv_check) 2132 2133/* Vector Floating-Point MIN/MAX Instructions */ 2134GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2135GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2136GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2137GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2138 2139/* Vector Floating-Point Sign-Injection Instructions */ 2140GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2141GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2142GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2143GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2144GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2145GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2146 2147/* Vector Floating-Point Compare Instructions */ 2148static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2149{ 2150 return (vext_check_isa_ill(s) && 2151 vext_check_reg(s, a->rs2, false) && 2152 vext_check_reg(s, a->rs1, false) && 2153 (s->sew != 0) && 2154 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 2155 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 2156 (s->lmul == 0))); 2157} 2158 2159GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2160GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2161GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2162GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2163GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) 2164 2165static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2166{ 2167 return (vext_check_isa_ill(s) && 2168 vext_check_reg(s, a->rs2, false) && 2169 (s->sew != 0) && 2170 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 2171 (s->lmul == 0))); 2172} 2173 2174GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2175GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2176GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2177GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2178GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2179GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2180GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) 2181 2182/* Vector Floating-Point Classify Instruction */ 2183GEN_OPFV_TRANS(vfclass_v, opfv_check) 2184 2185/* Vector Floating-Point Merge Instruction */ 2186GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2187 2188static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2189{ 2190 if (vext_check_isa_ill(s) && 2191 vext_check_reg(s, a->rd, false) && 2192 (s->sew != 0)) { 2193 2194 if (s->vl_eq_vlmax) { 2195 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2196 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); 2197 mark_vs_dirty(s); 2198 } else { 2199 TCGv_ptr dest; 2200 TCGv_i32 desc; 2201 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2202 static gen_helper_vmv_vx * const fns[3] = { 2203 gen_helper_vmv_v_x_h, 2204 gen_helper_vmv_v_x_w, 2205 gen_helper_vmv_v_x_d, 2206 }; 2207 TCGLabel *over = gen_new_label(); 2208 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2209 2210 dest = tcg_temp_new_ptr(); 2211 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2212 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2213 fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); 2214 2215 tcg_temp_free_ptr(dest); 2216 mark_vs_dirty(s); 2217 gen_set_label(over); 2218 } 2219 return true; 2220 } 2221 return false; 2222} 2223 2224/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2225GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) 2226GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) 2227GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) 2228GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) 2229 2230/* Widening Floating-Point/Integer Type-Convert Instructions */ 2231 2232/* 2233 * If the current SEW does not correspond to a supported IEEE floating-point 2234 * type, an illegal instruction exception is raised 2235 */ 2236static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2237{ 2238 return (vext_check_isa_ill(s) && 2239 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2240 vext_check_reg(s, a->rd, true) && 2241 vext_check_reg(s, a->rs2, false) && 2242 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 2243 1 << s->lmul) && 2244 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2245} 2246 2247#define GEN_OPFV_WIDEN_TRANS(NAME) \ 2248static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2249{ \ 2250 if (opfv_widen_check(s, a)) { \ 2251 uint32_t data = 0; \ 2252 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2253 gen_helper_##NAME##_h, \ 2254 gen_helper_##NAME##_w, \ 2255 }; \ 2256 TCGLabel *over = gen_new_label(); \ 2257 gen_set_rm(s, 7); \ 2258 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2259 \ 2260 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2261 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2262 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2263 vreg_ofs(s, a->rs2), cpu_env, \ 2264 s->vlen / 8, s->vlen / 8, data, \ 2265 fns[s->sew - 1]); \ 2266 mark_vs_dirty(s); \ 2267 gen_set_label(over); \ 2268 return true; \ 2269 } \ 2270 return false; \ 2271} 2272 2273GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) 2274GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) 2275GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) 2276GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) 2277GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) 2278 2279/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2280 2281/* 2282 * If the current SEW does not correspond to a supported IEEE floating-point 2283 * type, an illegal instruction exception is raised 2284 */ 2285static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2286{ 2287 return (vext_check_isa_ill(s) && 2288 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2289 vext_check_reg(s, a->rd, false) && 2290 vext_check_reg(s, a->rs2, true) && 2291 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 2292 2 << s->lmul) && 2293 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2294} 2295 2296#define GEN_OPFV_NARROW_TRANS(NAME) \ 2297static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2298{ \ 2299 if (opfv_narrow_check(s, a)) { \ 2300 uint32_t data = 0; \ 2301 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2302 gen_helper_##NAME##_h, \ 2303 gen_helper_##NAME##_w, \ 2304 }; \ 2305 TCGLabel *over = gen_new_label(); \ 2306 gen_set_rm(s, 7); \ 2307 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2308 \ 2309 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2310 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2311 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2312 vreg_ofs(s, a->rs2), cpu_env, \ 2313 s->vlen / 8, s->vlen / 8, data, \ 2314 fns[s->sew - 1]); \ 2315 mark_vs_dirty(s); \ 2316 gen_set_label(over); \ 2317 return true; \ 2318 } \ 2319 return false; \ 2320} 2321 2322GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) 2323GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) 2324GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) 2325GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) 2326GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) 2327 2328/* 2329 *** Vector Reduction Operations 2330 */ 2331/* Vector Single-Width Integer Reduction Instructions */ 2332static bool reduction_check(DisasContext *s, arg_rmrr *a) 2333{ 2334 return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false); 2335} 2336 2337GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2338GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2339GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2340GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2341GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2342GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2343GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2344GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2345 2346/* Vector Widening Integer Reduction Instructions */ 2347GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check) 2348GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) 2349 2350/* Vector Single-Width Floating-Point Reduction Instructions */ 2351GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) 2352GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) 2353GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) 2354 2355/* Vector Widening Floating-Point Reduction Instructions */ 2356GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) 2357 2358/* 2359 *** Vector Mask Operations 2360 */ 2361 2362/* Vector Mask-Register Logical Instructions */ 2363#define GEN_MM_TRANS(NAME) \ 2364static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2365{ \ 2366 if (vext_check_isa_ill(s)) { \ 2367 uint32_t data = 0; \ 2368 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2369 TCGLabel *over = gen_new_label(); \ 2370 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2371 \ 2372 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2373 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2374 vreg_ofs(s, a->rs1), \ 2375 vreg_ofs(s, a->rs2), cpu_env, \ 2376 s->vlen / 8, s->vlen / 8, data, fn); \ 2377 mark_vs_dirty(s); \ 2378 gen_set_label(over); \ 2379 return true; \ 2380 } \ 2381 return false; \ 2382} 2383 2384GEN_MM_TRANS(vmand_mm) 2385GEN_MM_TRANS(vmnand_mm) 2386GEN_MM_TRANS(vmandnot_mm) 2387GEN_MM_TRANS(vmxor_mm) 2388GEN_MM_TRANS(vmor_mm) 2389GEN_MM_TRANS(vmnor_mm) 2390GEN_MM_TRANS(vmornot_mm) 2391GEN_MM_TRANS(vmxnor_mm) 2392 2393/* Vector mask population count vmpopc */ 2394static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) 2395{ 2396 if (vext_check_isa_ill(s)) { 2397 TCGv_ptr src2, mask; 2398 TCGv dst; 2399 TCGv_i32 desc; 2400 uint32_t data = 0; 2401 data = FIELD_DP32(data, VDATA, VM, a->vm); 2402 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2403 2404 mask = tcg_temp_new_ptr(); 2405 src2 = tcg_temp_new_ptr(); 2406 dst = dest_gpr(s, a->rd); 2407 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2408 2409 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2410 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2411 2412 gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc); 2413 gen_set_gpr(s, a->rd, dst); 2414 2415 tcg_temp_free_ptr(mask); 2416 tcg_temp_free_ptr(src2); 2417 return true; 2418 } 2419 return false; 2420} 2421 2422/* vmfirst find-first-set mask bit */ 2423static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) 2424{ 2425 if (vext_check_isa_ill(s)) { 2426 TCGv_ptr src2, mask; 2427 TCGv dst; 2428 TCGv_i32 desc; 2429 uint32_t data = 0; 2430 data = FIELD_DP32(data, VDATA, VM, a->vm); 2431 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2432 2433 mask = tcg_temp_new_ptr(); 2434 src2 = tcg_temp_new_ptr(); 2435 dst = dest_gpr(s, a->rd); 2436 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2437 2438 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2439 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2440 2441 gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc); 2442 gen_set_gpr(s, a->rd, dst); 2443 2444 tcg_temp_free_ptr(mask); 2445 tcg_temp_free_ptr(src2); 2446 return true; 2447 } 2448 return false; 2449} 2450 2451/* vmsbf.m set-before-first mask bit */ 2452/* vmsif.m set-includ-first mask bit */ 2453/* vmsof.m set-only-first mask bit */ 2454#define GEN_M_TRANS(NAME) \ 2455static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2456{ \ 2457 if (vext_check_isa_ill(s)) { \ 2458 uint32_t data = 0; \ 2459 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2460 TCGLabel *over = gen_new_label(); \ 2461 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2462 \ 2463 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2464 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2465 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2466 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2467 cpu_env, s->vlen / 8, s->vlen / 8, \ 2468 data, fn); \ 2469 mark_vs_dirty(s); \ 2470 gen_set_label(over); \ 2471 return true; \ 2472 } \ 2473 return false; \ 2474} 2475 2476GEN_M_TRANS(vmsbf_m) 2477GEN_M_TRANS(vmsif_m) 2478GEN_M_TRANS(vmsof_m) 2479 2480/* Vector Iota Instruction */ 2481static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2482{ 2483 if (vext_check_isa_ill(s) && 2484 vext_check_reg(s, a->rd, false) && 2485 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) && 2486 (a->vm != 0 || a->rd != 0)) { 2487 uint32_t data = 0; 2488 TCGLabel *over = gen_new_label(); 2489 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2490 2491 data = FIELD_DP32(data, VDATA, VM, a->vm); 2492 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2493 static gen_helper_gvec_3_ptr * const fns[4] = { 2494 gen_helper_viota_m_b, gen_helper_viota_m_h, 2495 gen_helper_viota_m_w, gen_helper_viota_m_d, 2496 }; 2497 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2498 vreg_ofs(s, a->rs2), cpu_env, 2499 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 2500 mark_vs_dirty(s); 2501 gen_set_label(over); 2502 return true; 2503 } 2504 return false; 2505} 2506 2507/* Vector Element Index Instruction */ 2508static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 2509{ 2510 if (vext_check_isa_ill(s) && 2511 vext_check_reg(s, a->rd, false) && 2512 vext_check_overlap_mask(s, a->rd, a->vm, false)) { 2513 uint32_t data = 0; 2514 TCGLabel *over = gen_new_label(); 2515 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2516 2517 data = FIELD_DP32(data, VDATA, VM, a->vm); 2518 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2519 static gen_helper_gvec_2_ptr * const fns[4] = { 2520 gen_helper_vid_v_b, gen_helper_vid_v_h, 2521 gen_helper_vid_v_w, gen_helper_vid_v_d, 2522 }; 2523 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2524 cpu_env, s->vlen / 8, s->vlen / 8, 2525 data, fns[s->sew]); 2526 mark_vs_dirty(s); 2527 gen_set_label(over); 2528 return true; 2529 } 2530 return false; 2531} 2532 2533/* 2534 *** Vector Permutation Instructions 2535 */ 2536 2537/* Integer Extract Instruction */ 2538 2539static void load_element(TCGv_i64 dest, TCGv_ptr base, 2540 int ofs, int sew) 2541{ 2542 switch (sew) { 2543 case MO_8: 2544 tcg_gen_ld8u_i64(dest, base, ofs); 2545 break; 2546 case MO_16: 2547 tcg_gen_ld16u_i64(dest, base, ofs); 2548 break; 2549 case MO_32: 2550 tcg_gen_ld32u_i64(dest, base, ofs); 2551 break; 2552 case MO_64: 2553 tcg_gen_ld_i64(dest, base, ofs); 2554 break; 2555 default: 2556 g_assert_not_reached(); 2557 break; 2558 } 2559} 2560 2561/* offset of the idx element with base regsiter r */ 2562static uint32_t endian_ofs(DisasContext *s, int r, int idx) 2563{ 2564#ifdef HOST_WORDS_BIGENDIAN 2565 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 2566#else 2567 return vreg_ofs(s, r) + (idx << s->sew); 2568#endif 2569} 2570 2571/* adjust the index according to the endian */ 2572static void endian_adjust(TCGv_i32 ofs, int sew) 2573{ 2574#ifdef HOST_WORDS_BIGENDIAN 2575 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 2576#endif 2577} 2578 2579/* Load idx >= VLMAX ? 0 : vreg[idx] */ 2580static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 2581 int vreg, TCGv idx, int vlmax) 2582{ 2583 TCGv_i32 ofs = tcg_temp_new_i32(); 2584 TCGv_ptr base = tcg_temp_new_ptr(); 2585 TCGv_i64 t_idx = tcg_temp_new_i64(); 2586 TCGv_i64 t_vlmax, t_zero; 2587 2588 /* 2589 * Mask the index to the length so that we do 2590 * not produce an out-of-range load. 2591 */ 2592 tcg_gen_trunc_tl_i32(ofs, idx); 2593 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 2594 2595 /* Convert the index to an offset. */ 2596 endian_adjust(ofs, s->sew); 2597 tcg_gen_shli_i32(ofs, ofs, s->sew); 2598 2599 /* Convert the index to a pointer. */ 2600 tcg_gen_ext_i32_ptr(base, ofs); 2601 tcg_gen_add_ptr(base, base, cpu_env); 2602 2603 /* Perform the load. */ 2604 load_element(dest, base, 2605 vreg_ofs(s, vreg), s->sew); 2606 tcg_temp_free_ptr(base); 2607 tcg_temp_free_i32(ofs); 2608 2609 /* Flush out-of-range indexing to zero. */ 2610 t_vlmax = tcg_constant_i64(vlmax); 2611 t_zero = tcg_constant_i64(0); 2612 tcg_gen_extu_tl_i64(t_idx, idx); 2613 2614 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 2615 t_vlmax, dest, t_zero); 2616 2617 tcg_temp_free_i64(t_idx); 2618} 2619 2620static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 2621 int vreg, int idx) 2622{ 2623 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2624} 2625 2626static bool trans_vext_x_v(DisasContext *s, arg_r *a) 2627{ 2628 TCGv_i64 tmp = tcg_temp_new_i64(); 2629 TCGv dest = dest_gpr(s, a->rd); 2630 2631 if (a->rs1 == 0) { 2632 /* Special case vmv.x.s rd, vs2. */ 2633 vec_element_loadi(s, tmp, a->rs2, 0); 2634 } else { 2635 /* This instruction ignores LMUL and vector register groups */ 2636 int vlmax = s->vlen >> (3 + s->sew); 2637 vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); 2638 } 2639 2640 tcg_gen_trunc_i64_tl(dest, tmp); 2641 gen_set_gpr(s, a->rd, dest); 2642 2643 tcg_temp_free_i64(tmp); 2644 return true; 2645} 2646 2647/* Integer Scalar Move Instruction */ 2648 2649static void store_element(TCGv_i64 val, TCGv_ptr base, 2650 int ofs, int sew) 2651{ 2652 switch (sew) { 2653 case MO_8: 2654 tcg_gen_st8_i64(val, base, ofs); 2655 break; 2656 case MO_16: 2657 tcg_gen_st16_i64(val, base, ofs); 2658 break; 2659 case MO_32: 2660 tcg_gen_st32_i64(val, base, ofs); 2661 break; 2662 case MO_64: 2663 tcg_gen_st_i64(val, base, ofs); 2664 break; 2665 default: 2666 g_assert_not_reached(); 2667 break; 2668 } 2669} 2670 2671/* 2672 * Store vreg[idx] = val. 2673 * The index must be in range of VLMAX. 2674 */ 2675static void vec_element_storei(DisasContext *s, int vreg, 2676 int idx, TCGv_i64 val) 2677{ 2678 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2679} 2680 2681/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 2682static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 2683{ 2684 if (vext_check_isa_ill(s)) { 2685 /* This instruction ignores LMUL and vector register groups */ 2686 int maxsz = s->vlen >> 3; 2687 TCGv_i64 t1; 2688 TCGLabel *over = gen_new_label(); 2689 2690 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2691 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); 2692 if (a->rs1 == 0) { 2693 goto done; 2694 } 2695 2696 t1 = tcg_temp_new_i64(); 2697 tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); 2698 vec_element_storei(s, a->rd, 0, t1); 2699 tcg_temp_free_i64(t1); 2700 mark_vs_dirty(s); 2701 done: 2702 gen_set_label(over); 2703 return true; 2704 } 2705 return false; 2706} 2707 2708/* Floating-Point Scalar Move Instructions */ 2709static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 2710{ 2711 if (!s->vill && has_ext(s, RVF) && 2712 (s->mstatus_fs != 0) && (s->sew != 0)) { 2713 unsigned int len = 8 << s->sew; 2714 2715 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); 2716 if (len < 64) { 2717 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 2718 MAKE_64BIT_MASK(len, 64 - len)); 2719 } 2720 2721 mark_fs_dirty(s); 2722 return true; 2723 } 2724 return false; 2725} 2726 2727/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 2728static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 2729{ 2730 if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { 2731 TCGv_i64 t1; 2732 /* The instructions ignore LMUL and vector register group. */ 2733 uint32_t vlmax = s->vlen >> 3; 2734 2735 /* if vl == 0, skip vector register write back */ 2736 TCGLabel *over = gen_new_label(); 2737 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2738 2739 /* zeroed all elements */ 2740 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); 2741 2742 /* NaN-box f[rs1] as necessary for SEW */ 2743 t1 = tcg_temp_new_i64(); 2744 if (s->sew == MO_64 && !has_ext(s, RVD)) { 2745 tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); 2746 } else { 2747 tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); 2748 } 2749 vec_element_storei(s, a->rd, 0, t1); 2750 tcg_temp_free_i64(t1); 2751 mark_vs_dirty(s); 2752 gen_set_label(over); 2753 return true; 2754 } 2755 return false; 2756} 2757 2758/* Vector Slide Instructions */ 2759static bool slideup_check(DisasContext *s, arg_rmrr *a) 2760{ 2761 return (vext_check_isa_ill(s) && 2762 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2763 vext_check_reg(s, a->rd, false) && 2764 vext_check_reg(s, a->rs2, false) && 2765 (a->rd != a->rs2)); 2766} 2767 2768GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 2769GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 2770GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check) 2771 2772GEN_OPIVX_TRANS(vslidedown_vx, opivx_check) 2773GEN_OPIVX_TRANS(vslide1down_vx, opivx_check) 2774GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check) 2775 2776/* Vector Register Gather Instruction */ 2777static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 2778{ 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->rs1, false) && 2783 vext_check_reg(s, a->rs2, false) && 2784 (a->rd != a->rs2) && (a->rd != a->rs1)); 2785} 2786 2787GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 2788 2789static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 2790{ 2791 return (vext_check_isa_ill(s) && 2792 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2793 vext_check_reg(s, a->rd, false) && 2794 vext_check_reg(s, a->rs2, false) && 2795 (a->rd != a->rs2)); 2796} 2797 2798/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 2799static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 2800{ 2801 if (!vrgather_vx_check(s, a)) { 2802 return false; 2803 } 2804 2805 if (a->vm && s->vl_eq_vlmax) { 2806 int vlmax = s->vlen; 2807 TCGv_i64 dest = tcg_temp_new_i64(); 2808 2809 if (a->rs1 == 0) { 2810 vec_element_loadi(s, dest, a->rs2, 0); 2811 } else { 2812 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 2813 } 2814 2815 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2816 MAXSZ(s), MAXSZ(s), dest); 2817 tcg_temp_free_i64(dest); 2818 mark_vs_dirty(s); 2819 } else { 2820 static gen_helper_opivx * const fns[4] = { 2821 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2822 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2823 }; 2824 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 2825 } 2826 return true; 2827} 2828 2829/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 2830static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 2831{ 2832 if (!vrgather_vx_check(s, a)) { 2833 return false; 2834 } 2835 2836 if (a->vm && s->vl_eq_vlmax) { 2837 if (a->rs1 >= s->vlen) { 2838 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), 2839 MAXSZ(s), MAXSZ(s), 0); 2840 } else { 2841 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 2842 endian_ofs(s, a->rs2, a->rs1), 2843 MAXSZ(s), MAXSZ(s)); 2844 } 2845 mark_vs_dirty(s); 2846 } else { 2847 static gen_helper_opivx * const fns[4] = { 2848 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2849 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2850 }; 2851 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1); 2852 } 2853 return true; 2854} 2855 2856/* Vector Compress Instruction */ 2857static bool vcompress_vm_check(DisasContext *s, arg_r *a) 2858{ 2859 return (vext_check_isa_ill(s) && 2860 vext_check_reg(s, a->rd, false) && 2861 vext_check_reg(s, a->rs2, false) && 2862 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) && 2863 (a->rd != a->rs2)); 2864} 2865 2866static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 2867{ 2868 if (vcompress_vm_check(s, a)) { 2869 uint32_t data = 0; 2870 static gen_helper_gvec_4_ptr * const fns[4] = { 2871 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 2872 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 2873 }; 2874 TCGLabel *over = gen_new_label(); 2875 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2876 2877 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2878 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2879 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 2880 cpu_env, s->vlen / 8, s->vlen / 8, data, 2881 fns[s->sew]); 2882 mark_vs_dirty(s); 2883 gen_set_label(over); 2884 return true; 2885 } 2886 return false; 2887} 2888