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