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(0, 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(0, 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(0, 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(0, 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(0, 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, 0, 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(0, 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(0, 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, 0, 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, 0, 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, 0, \ 1288 s->vlen / 8, data, fns[s->sew]); \ 1289 gen_set_label(over); \ 1290 return true; \ 1291 } \ 1292 return false; \ 1293} 1294 1295/* 1296 * For vadc and vsbc, an illegal instruction exception is raised if the 1297 * destination vector register is v0 and LMUL > 1. (Section 12.3) 1298 */ 1299static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1300{ 1301 return (vext_check_isa_ill(s) && 1302 vext_check_reg(s, a->rd, false) && 1303 vext_check_reg(s, a->rs2, false) && 1304 vext_check_reg(s, a->rs1, false) && 1305 ((a->rd != 0) || (s->lmul == 0))); 1306} 1307 1308GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1309GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1310 1311/* 1312 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1313 * destination vector register overlaps a source vector register group. 1314 */ 1315static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1316{ 1317 return (vext_check_isa_ill(s) && 1318 vext_check_reg(s, a->rs2, false) && 1319 vext_check_reg(s, a->rs1, false) && 1320 vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1321 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1322} 1323 1324GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1325GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1326 1327static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1328{ 1329 return (vext_check_isa_ill(s) && 1330 vext_check_reg(s, a->rd, false) && 1331 vext_check_reg(s, a->rs2, false) && 1332 ((a->rd != 0) || (s->lmul == 0))); 1333} 1334 1335/* OPIVX without GVEC IR */ 1336#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1337static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1338{ \ 1339 if (CHECK(s, a)) { \ 1340 static gen_helper_opivx * const fns[4] = { \ 1341 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1342 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1343 }; \ 1344 \ 1345 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1346 } \ 1347 return false; \ 1348} 1349 1350GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1351GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1352 1353static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1354{ 1355 return (vext_check_isa_ill(s) && 1356 vext_check_reg(s, a->rs2, false) && 1357 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1358} 1359 1360GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1361GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1362 1363/* OPIVI without GVEC IR */ 1364#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \ 1365static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1366{ \ 1367 if (CHECK(s, a)) { \ 1368 static gen_helper_opivx * const fns[4] = { \ 1369 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1370 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1371 }; \ 1372 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1373 fns[s->sew], s, ZX); \ 1374 } \ 1375 return false; \ 1376} 1377 1378GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check) 1379GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check) 1380 1381/* Vector Bitwise Logical Instructions */ 1382GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1383GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1384GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1385GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1386GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1387GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1388GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi) 1389GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori) 1390GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori) 1391 1392/* Vector Single-Width Bit Shift Instructions */ 1393GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1394GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1395GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1396 1397typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1398 uint32_t, uint32_t); 1399 1400static inline bool 1401do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1402 gen_helper_opivx *fn) 1403{ 1404 if (!opivx_check(s, a)) { 1405 return false; 1406 } 1407 1408 if (a->vm && s->vl_eq_vlmax) { 1409 TCGv_i32 src1 = tcg_temp_new_i32(); 1410 TCGv tmp = tcg_temp_new(); 1411 1412 gen_get_gpr(tmp, a->rs1); 1413 tcg_gen_trunc_tl_i32(src1, tmp); 1414 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1415 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1416 src1, MAXSZ(s), MAXSZ(s)); 1417 1418 tcg_temp_free_i32(src1); 1419 tcg_temp_free(tmp); 1420 return true; 1421 } 1422 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1423} 1424 1425#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1426static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1427{ \ 1428 static gen_helper_opivx * const fns[4] = { \ 1429 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1430 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1431 }; \ 1432 \ 1433 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1434} 1435 1436GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1437GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1438GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1439 1440GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli) 1441GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri) 1442GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari) 1443 1444/* Vector Narrowing Integer Right Shift Instructions */ 1445static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) 1446{ 1447 return (vext_check_isa_ill(s) && 1448 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1449 vext_check_reg(s, a->rd, false) && 1450 vext_check_reg(s, a->rs2, true) && 1451 vext_check_reg(s, a->rs1, false) && 1452 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1453 2 << s->lmul) && 1454 (s->lmul < 0x3) && (s->sew < 0x3)); 1455} 1456 1457/* OPIVV with NARROW */ 1458#define GEN_OPIVV_NARROW_TRANS(NAME) \ 1459static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1460{ \ 1461 if (opivv_narrow_check(s, a)) { \ 1462 uint32_t data = 0; \ 1463 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1464 gen_helper_##NAME##_b, \ 1465 gen_helper_##NAME##_h, \ 1466 gen_helper_##NAME##_w, \ 1467 }; \ 1468 TCGLabel *over = gen_new_label(); \ 1469 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1470 \ 1471 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1472 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1473 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1474 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1475 vreg_ofs(s, a->rs1), \ 1476 vreg_ofs(s, a->rs2), cpu_env, 0, \ 1477 s->vlen / 8, data, fns[s->sew]); \ 1478 gen_set_label(over); \ 1479 return true; \ 1480 } \ 1481 return false; \ 1482} 1483GEN_OPIVV_NARROW_TRANS(vnsra_vv) 1484GEN_OPIVV_NARROW_TRANS(vnsrl_vv) 1485 1486static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) 1487{ 1488 return (vext_check_isa_ill(s) && 1489 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1490 vext_check_reg(s, a->rd, false) && 1491 vext_check_reg(s, a->rs2, true) && 1492 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1493 2 << s->lmul) && 1494 (s->lmul < 0x3) && (s->sew < 0x3)); 1495} 1496 1497/* OPIVX with NARROW */ 1498#define GEN_OPIVX_NARROW_TRANS(NAME) \ 1499static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1500{ \ 1501 if (opivx_narrow_check(s, a)) { \ 1502 static gen_helper_opivx * const fns[3] = { \ 1503 gen_helper_##NAME##_b, \ 1504 gen_helper_##NAME##_h, \ 1505 gen_helper_##NAME##_w, \ 1506 }; \ 1507 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1508 } \ 1509 return false; \ 1510} 1511 1512GEN_OPIVX_NARROW_TRANS(vnsra_vx) 1513GEN_OPIVX_NARROW_TRANS(vnsrl_vx) 1514 1515/* OPIVI with NARROW */ 1516#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \ 1517static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1518{ \ 1519 if (opivx_narrow_check(s, a)) { \ 1520 static gen_helper_opivx * const fns[3] = { \ 1521 gen_helper_##OPIVX##_b, \ 1522 gen_helper_##OPIVX##_h, \ 1523 gen_helper_##OPIVX##_w, \ 1524 }; \ 1525 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1526 fns[s->sew], s, ZX); \ 1527 } \ 1528 return false; \ 1529} 1530 1531GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx) 1532GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx) 1533 1534/* Vector Integer Comparison Instructions */ 1535/* 1536 * For all comparison instructions, an illegal instruction exception is raised 1537 * if the destination vector register overlaps a source vector register group 1538 * and LMUL > 1. 1539 */ 1540static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1541{ 1542 return (vext_check_isa_ill(s) && 1543 vext_check_reg(s, a->rs2, false) && 1544 vext_check_reg(s, a->rs1, false) && 1545 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1546 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 1547 (s->lmul == 0))); 1548} 1549GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1550GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1551GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1552GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1553GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1554GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1555 1556static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1557{ 1558 return (vext_check_isa_ill(s) && 1559 vext_check_reg(s, a->rs2, false) && 1560 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 1561 (s->lmul == 0))); 1562} 1563 1564GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1565GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1566GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1567GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1568GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1569GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1570GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1571GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1572 1573GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check) 1574GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check) 1575GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check) 1576GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check) 1577GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check) 1578GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check) 1579 1580/* Vector Integer Min/Max Instructions */ 1581GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1582GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1583GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1584GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1585GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1586GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1587GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1588GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1589 1590/* Vector Single-Width Integer Multiply Instructions */ 1591GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1592GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1593GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1594GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1595GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1596GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1597GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1598GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1599 1600/* Vector Integer Divide Instructions */ 1601GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1602GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1603GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1604GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1605GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1606GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1607GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1608GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1609 1610/* Vector Widening Integer Multiply Instructions */ 1611GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1612GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1613GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1614GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1615GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1616GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1617 1618/* Vector Single-Width Integer Multiply-Add Instructions */ 1619GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1620GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1621GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1622GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1623GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1624GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1625GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1626GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1627 1628/* Vector Widening Integer Multiply-Add Instructions */ 1629GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1630GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1631GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1632GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1633GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1634GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1635GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1636 1637/* Vector Integer Merge and Move Instructions */ 1638static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1639{ 1640 if (vext_check_isa_ill(s) && 1641 vext_check_reg(s, a->rd, false) && 1642 vext_check_reg(s, a->rs1, false)) { 1643 1644 if (s->vl_eq_vlmax) { 1645 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1646 vreg_ofs(s, a->rs1), 1647 MAXSZ(s), MAXSZ(s)); 1648 } else { 1649 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1650 static gen_helper_gvec_2_ptr * const fns[4] = { 1651 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1652 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1653 }; 1654 TCGLabel *over = gen_new_label(); 1655 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1656 1657 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1658 cpu_env, 0, s->vlen / 8, data, fns[s->sew]); 1659 gen_set_label(over); 1660 } 1661 return true; 1662 } 1663 return false; 1664} 1665 1666typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1667static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1668{ 1669 if (vext_check_isa_ill(s) && 1670 vext_check_reg(s, a->rd, false)) { 1671 1672 TCGv s1; 1673 TCGLabel *over = gen_new_label(); 1674 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1675 1676 s1 = tcg_temp_new(); 1677 gen_get_gpr(s1, a->rs1); 1678 1679 if (s->vl_eq_vlmax) { 1680 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 1681 MAXSZ(s), MAXSZ(s), s1); 1682 } else { 1683 TCGv_i32 desc ; 1684 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 1685 TCGv_ptr dest = tcg_temp_new_ptr(); 1686 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1687 static gen_helper_vmv_vx * const fns[4] = { 1688 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1689 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1690 }; 1691 1692 tcg_gen_ext_tl_i64(s1_i64, s1); 1693 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 1694 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1695 fns[s->sew](dest, s1_i64, cpu_env, desc); 1696 1697 tcg_temp_free_ptr(dest); 1698 tcg_temp_free_i32(desc); 1699 tcg_temp_free_i64(s1_i64); 1700 } 1701 1702 tcg_temp_free(s1); 1703 gen_set_label(over); 1704 return true; 1705 } 1706 return false; 1707} 1708 1709static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 1710{ 1711 if (vext_check_isa_ill(s) && 1712 vext_check_reg(s, a->rd, false)) { 1713 1714 int64_t simm = sextract64(a->rs1, 0, 5); 1715 if (s->vl_eq_vlmax) { 1716 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 1717 MAXSZ(s), MAXSZ(s), simm); 1718 } else { 1719 TCGv_i32 desc; 1720 TCGv_i64 s1; 1721 TCGv_ptr dest; 1722 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1723 static gen_helper_vmv_vx * const fns[4] = { 1724 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1725 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1726 }; 1727 TCGLabel *over = gen_new_label(); 1728 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1729 1730 s1 = tcg_const_i64(simm); 1731 dest = tcg_temp_new_ptr(); 1732 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 1733 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1734 fns[s->sew](dest, s1, cpu_env, desc); 1735 1736 tcg_temp_free_ptr(dest); 1737 tcg_temp_free_i32(desc); 1738 tcg_temp_free_i64(s1); 1739 gen_set_label(over); 1740 } 1741 return true; 1742 } 1743 return false; 1744} 1745 1746GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 1747GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 1748GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check) 1749 1750/* 1751 *** Vector Fixed-Point Arithmetic Instructions 1752 */ 1753 1754/* Vector Single-Width Saturating Add and Subtract */ 1755GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 1756GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 1757GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 1758GEN_OPIVV_TRANS(vssub_vv, opivv_check) 1759GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 1760GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 1761GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 1762GEN_OPIVX_TRANS(vssub_vx, opivx_check) 1763GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check) 1764GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check) 1765 1766/* Vector Single-Width Averaging Add and Subtract */ 1767GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 1768GEN_OPIVV_TRANS(vasub_vv, opivv_check) 1769GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 1770GEN_OPIVX_TRANS(vasub_vx, opivx_check) 1771GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) 1772 1773/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 1774GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 1775GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 1776 1777/* Vector Widening Saturating Scaled Multiply-Add */ 1778GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) 1779GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) 1780GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) 1781GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) 1782GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) 1783GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) 1784GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) 1785 1786/* Vector Single-Width Scaling Shift Instructions */ 1787GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 1788GEN_OPIVV_TRANS(vssra_vv, opivv_check) 1789GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 1790GEN_OPIVX_TRANS(vssra_vx, opivx_check) 1791GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check) 1792GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check) 1793 1794/* Vector Narrowing Fixed-Point Clip Instructions */ 1795GEN_OPIVV_NARROW_TRANS(vnclipu_vv) 1796GEN_OPIVV_NARROW_TRANS(vnclip_vv) 1797GEN_OPIVX_NARROW_TRANS(vnclipu_vx) 1798GEN_OPIVX_NARROW_TRANS(vnclip_vx) 1799GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx) 1800GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx) 1801 1802/* 1803 *** Vector Float Point Arithmetic Instructions 1804 */ 1805/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 1806 1807/* 1808 * If the current SEW does not correspond to a supported IEEE floating-point 1809 * type, an illegal instruction exception is raised. 1810 */ 1811static bool opfvv_check(DisasContext *s, arg_rmrr *a) 1812{ 1813 return (vext_check_isa_ill(s) && 1814 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1815 vext_check_reg(s, a->rd, false) && 1816 vext_check_reg(s, a->rs2, false) && 1817 vext_check_reg(s, a->rs1, false) && 1818 (s->sew != 0)); 1819} 1820 1821/* OPFVV without GVEC IR */ 1822#define GEN_OPFVV_TRANS(NAME, CHECK) \ 1823static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1824{ \ 1825 if (CHECK(s, a)) { \ 1826 uint32_t data = 0; \ 1827 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1828 gen_helper_##NAME##_h, \ 1829 gen_helper_##NAME##_w, \ 1830 gen_helper_##NAME##_d, \ 1831 }; \ 1832 TCGLabel *over = gen_new_label(); \ 1833 gen_set_rm(s, 7); \ 1834 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1835 \ 1836 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1837 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1838 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1839 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1840 vreg_ofs(s, a->rs1), \ 1841 vreg_ofs(s, a->rs2), cpu_env, 0, \ 1842 s->vlen / 8, data, fns[s->sew - 1]); \ 1843 gen_set_label(over); \ 1844 return true; \ 1845 } \ 1846 return false; \ 1847} 1848GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 1849GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 1850 1851typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 1852 TCGv_env, TCGv_i32); 1853 1854static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 1855 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 1856{ 1857 TCGv_ptr dest, src2, mask; 1858 TCGv_i32 desc; 1859 1860 TCGLabel *over = gen_new_label(); 1861 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1862 1863 dest = tcg_temp_new_ptr(); 1864 mask = tcg_temp_new_ptr(); 1865 src2 = tcg_temp_new_ptr(); 1866 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 1867 1868 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1869 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1870 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1871 1872 fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc); 1873 1874 tcg_temp_free_ptr(dest); 1875 tcg_temp_free_ptr(mask); 1876 tcg_temp_free_ptr(src2); 1877 tcg_temp_free_i32(desc); 1878 gen_set_label(over); 1879 return true; 1880} 1881 1882static bool opfvf_check(DisasContext *s, arg_rmrr *a) 1883{ 1884/* 1885 * If the current SEW does not correspond to a supported IEEE floating-point 1886 * type, an illegal instruction exception is raised 1887 */ 1888 return (vext_check_isa_ill(s) && 1889 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1890 vext_check_reg(s, a->rd, false) && 1891 vext_check_reg(s, a->rs2, false) && 1892 (s->sew != 0)); 1893} 1894 1895/* OPFVF without GVEC IR */ 1896#define GEN_OPFVF_TRANS(NAME, CHECK) \ 1897static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1898{ \ 1899 if (CHECK(s, a)) { \ 1900 uint32_t data = 0; \ 1901 static gen_helper_opfvf *const fns[3] = { \ 1902 gen_helper_##NAME##_h, \ 1903 gen_helper_##NAME##_w, \ 1904 gen_helper_##NAME##_d, \ 1905 }; \ 1906 gen_set_rm(s, 7); \ 1907 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1908 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1909 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1910 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1911 fns[s->sew - 1], s); \ 1912 } \ 1913 return false; \ 1914} 1915 1916GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 1917GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 1918GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 1919 1920/* Vector Widening Floating-Point Add/Subtract Instructions */ 1921static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 1922{ 1923 return (vext_check_isa_ill(s) && 1924 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1925 vext_check_reg(s, a->rd, true) && 1926 vext_check_reg(s, a->rs2, false) && 1927 vext_check_reg(s, a->rs1, false) && 1928 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1929 1 << s->lmul) && 1930 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1931 1 << s->lmul) && 1932 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1933} 1934 1935/* OPFVV with WIDEN */ 1936#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 1937static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1938{ \ 1939 if (CHECK(s, a)) { \ 1940 uint32_t data = 0; \ 1941 static gen_helper_gvec_4_ptr * const fns[2] = { \ 1942 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1943 }; \ 1944 TCGLabel *over = gen_new_label(); \ 1945 gen_set_rm(s, 7); \ 1946 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1947 \ 1948 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1949 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1950 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1951 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1952 vreg_ofs(s, a->rs1), \ 1953 vreg_ofs(s, a->rs2), cpu_env, 0, \ 1954 s->vlen / 8, data, fns[s->sew - 1]); \ 1955 gen_set_label(over); \ 1956 return true; \ 1957 } \ 1958 return false; \ 1959} 1960 1961GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 1962GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 1963 1964static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 1965{ 1966 return (vext_check_isa_ill(s) && 1967 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1968 vext_check_reg(s, a->rd, true) && 1969 vext_check_reg(s, a->rs2, false) && 1970 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1971 1 << s->lmul) && 1972 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1973} 1974 1975/* OPFVF with WIDEN */ 1976#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 1977static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1978{ \ 1979 if (opfvf_widen_check(s, a)) { \ 1980 uint32_t data = 0; \ 1981 static gen_helper_opfvf *const fns[2] = { \ 1982 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1983 }; \ 1984 gen_set_rm(s, 7); \ 1985 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1986 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1987 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1988 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1989 fns[s->sew - 1], s); \ 1990 } \ 1991 return false; \ 1992} 1993 1994GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 1995GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 1996 1997static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 1998{ 1999 return (vext_check_isa_ill(s) && 2000 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2001 vext_check_reg(s, a->rd, true) && 2002 vext_check_reg(s, a->rs2, true) && 2003 vext_check_reg(s, a->rs1, false) && 2004 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 2005 1 << s->lmul) && 2006 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2007} 2008 2009/* WIDEN OPFVV with WIDEN */ 2010#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2011static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2012{ \ 2013 if (opfwv_widen_check(s, a)) { \ 2014 uint32_t data = 0; \ 2015 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2016 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2017 }; \ 2018 TCGLabel *over = gen_new_label(); \ 2019 gen_set_rm(s, 7); \ 2020 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2021 \ 2022 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2023 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2024 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2025 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2026 vreg_ofs(s, a->rs1), \ 2027 vreg_ofs(s, a->rs2), cpu_env, 0, \ 2028 s->vlen / 8, data, fns[s->sew - 1]); \ 2029 gen_set_label(over); \ 2030 return true; \ 2031 } \ 2032 return false; \ 2033} 2034 2035GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2036GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2037 2038static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2039{ 2040 return (vext_check_isa_ill(s) && 2041 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2042 vext_check_reg(s, a->rd, true) && 2043 vext_check_reg(s, a->rs2, true) && 2044 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2045} 2046 2047/* WIDEN OPFVF with WIDEN */ 2048#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2049static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2050{ \ 2051 if (opfwf_widen_check(s, a)) { \ 2052 uint32_t data = 0; \ 2053 static gen_helper_opfvf *const fns[2] = { \ 2054 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2055 }; \ 2056 gen_set_rm(s, 7); \ 2057 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2058 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2059 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2060 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2061 fns[s->sew - 1], s); \ 2062 } \ 2063 return false; \ 2064} 2065 2066GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2067GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2068 2069/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2070GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2071GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2072GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2073GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2074GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2075 2076/* Vector Widening Floating-Point Multiply */ 2077GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2078GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2079 2080/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2081GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2082GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2083GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2084GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2085GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2086GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2087GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2088GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2089GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2090GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2091GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2092GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2093GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2094GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2095GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2096GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2097 2098/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2099GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2100GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2101GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2102GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2103GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2104GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2105GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2106GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2107 2108/* Vector Floating-Point Square-Root Instruction */ 2109 2110/* 2111 * If the current SEW does not correspond to a supported IEEE floating-point 2112 * type, an illegal instruction exception is raised 2113 */ 2114static bool opfv_check(DisasContext *s, arg_rmr *a) 2115{ 2116 return (vext_check_isa_ill(s) && 2117 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2118 vext_check_reg(s, a->rd, false) && 2119 vext_check_reg(s, a->rs2, false) && 2120 (s->sew != 0)); 2121} 2122 2123#define GEN_OPFV_TRANS(NAME, CHECK) \ 2124static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2125{ \ 2126 if (CHECK(s, a)) { \ 2127 uint32_t data = 0; \ 2128 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2129 gen_helper_##NAME##_h, \ 2130 gen_helper_##NAME##_w, \ 2131 gen_helper_##NAME##_d, \ 2132 }; \ 2133 TCGLabel *over = gen_new_label(); \ 2134 gen_set_rm(s, 7); \ 2135 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2136 \ 2137 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2138 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2139 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2140 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2141 vreg_ofs(s, a->rs2), cpu_env, 0, \ 2142 s->vlen / 8, data, fns[s->sew - 1]); \ 2143 gen_set_label(over); \ 2144 return true; \ 2145 } \ 2146 return false; \ 2147} 2148 2149GEN_OPFV_TRANS(vfsqrt_v, opfv_check) 2150 2151/* Vector Floating-Point MIN/MAX Instructions */ 2152GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2153GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2154GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2155GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2156 2157/* Vector Floating-Point Sign-Injection Instructions */ 2158GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2159GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2160GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2161GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2162GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2163GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2164 2165/* Vector Floating-Point Compare Instructions */ 2166static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2167{ 2168 return (vext_check_isa_ill(s) && 2169 vext_check_reg(s, a->rs2, false) && 2170 vext_check_reg(s, a->rs1, false) && 2171 (s->sew != 0) && 2172 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 2173 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 2174 (s->lmul == 0))); 2175} 2176 2177GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2178GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2179GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2180GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2181GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) 2182 2183static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2184{ 2185 return (vext_check_isa_ill(s) && 2186 vext_check_reg(s, a->rs2, false) && 2187 (s->sew != 0) && 2188 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 2189 (s->lmul == 0))); 2190} 2191 2192GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2193GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2194GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2195GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2196GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2197GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2198GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) 2199 2200/* Vector Floating-Point Classify Instruction */ 2201GEN_OPFV_TRANS(vfclass_v, opfv_check) 2202 2203/* Vector Floating-Point Merge Instruction */ 2204GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2205 2206static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2207{ 2208 if (vext_check_isa_ill(s) && 2209 vext_check_reg(s, a->rd, false) && 2210 (s->sew != 0)) { 2211 2212 if (s->vl_eq_vlmax) { 2213 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2214 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); 2215 } else { 2216 TCGv_ptr dest; 2217 TCGv_i32 desc; 2218 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2219 static gen_helper_vmv_vx * const fns[3] = { 2220 gen_helper_vmv_v_x_h, 2221 gen_helper_vmv_v_x_w, 2222 gen_helper_vmv_v_x_d, 2223 }; 2224 TCGLabel *over = gen_new_label(); 2225 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2226 2227 dest = tcg_temp_new_ptr(); 2228 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 2229 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2230 fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); 2231 2232 tcg_temp_free_ptr(dest); 2233 tcg_temp_free_i32(desc); 2234 gen_set_label(over); 2235 } 2236 return true; 2237 } 2238 return false; 2239} 2240 2241/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2242GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) 2243GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) 2244GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) 2245GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) 2246 2247/* Widening Floating-Point/Integer Type-Convert Instructions */ 2248 2249/* 2250 * If the current SEW does not correspond to a supported IEEE floating-point 2251 * type, an illegal instruction exception is raised 2252 */ 2253static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2254{ 2255 return (vext_check_isa_ill(s) && 2256 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2257 vext_check_reg(s, a->rd, true) && 2258 vext_check_reg(s, a->rs2, false) && 2259 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 2260 1 << s->lmul) && 2261 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2262} 2263 2264#define GEN_OPFV_WIDEN_TRANS(NAME) \ 2265static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2266{ \ 2267 if (opfv_widen_check(s, a)) { \ 2268 uint32_t data = 0; \ 2269 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2270 gen_helper_##NAME##_h, \ 2271 gen_helper_##NAME##_w, \ 2272 }; \ 2273 TCGLabel *over = gen_new_label(); \ 2274 gen_set_rm(s, 7); \ 2275 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2276 \ 2277 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2278 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2279 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2280 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2281 vreg_ofs(s, a->rs2), cpu_env, 0, \ 2282 s->vlen / 8, data, fns[s->sew - 1]); \ 2283 gen_set_label(over); \ 2284 return true; \ 2285 } \ 2286 return false; \ 2287} 2288 2289GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) 2290GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) 2291GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) 2292GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) 2293GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) 2294 2295/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2296 2297/* 2298 * If the current SEW does not correspond to a supported IEEE floating-point 2299 * type, an illegal instruction exception is raised 2300 */ 2301static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2302{ 2303 return (vext_check_isa_ill(s) && 2304 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2305 vext_check_reg(s, a->rd, false) && 2306 vext_check_reg(s, a->rs2, true) && 2307 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 2308 2 << s->lmul) && 2309 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2310} 2311 2312#define GEN_OPFV_NARROW_TRANS(NAME) \ 2313static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2314{ \ 2315 if (opfv_narrow_check(s, a)) { \ 2316 uint32_t data = 0; \ 2317 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2318 gen_helper_##NAME##_h, \ 2319 gen_helper_##NAME##_w, \ 2320 }; \ 2321 TCGLabel *over = gen_new_label(); \ 2322 gen_set_rm(s, 7); \ 2323 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2324 \ 2325 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2326 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2327 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2328 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2329 vreg_ofs(s, a->rs2), cpu_env, 0, \ 2330 s->vlen / 8, data, fns[s->sew - 1]); \ 2331 gen_set_label(over); \ 2332 return true; \ 2333 } \ 2334 return false; \ 2335} 2336 2337GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) 2338GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) 2339GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) 2340GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) 2341GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) 2342 2343/* 2344 *** Vector Reduction Operations 2345 */ 2346/* Vector Single-Width Integer Reduction Instructions */ 2347static bool reduction_check(DisasContext *s, arg_rmrr *a) 2348{ 2349 return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false); 2350} 2351 2352GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2353GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2354GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2355GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2356GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2357GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2358GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2359GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2360 2361/* Vector Widening Integer Reduction Instructions */ 2362GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check) 2363GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) 2364 2365/* Vector Single-Width Floating-Point Reduction Instructions */ 2366GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) 2367GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) 2368GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) 2369 2370/* Vector Widening Floating-Point Reduction Instructions */ 2371GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) 2372 2373/* 2374 *** Vector Mask Operations 2375 */ 2376 2377/* Vector Mask-Register Logical Instructions */ 2378#define GEN_MM_TRANS(NAME) \ 2379static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2380{ \ 2381 if (vext_check_isa_ill(s)) { \ 2382 uint32_t data = 0; \ 2383 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2384 TCGLabel *over = gen_new_label(); \ 2385 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2386 \ 2387 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2388 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2389 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2390 vreg_ofs(s, a->rs1), \ 2391 vreg_ofs(s, a->rs2), cpu_env, 0, \ 2392 s->vlen / 8, data, fn); \ 2393 gen_set_label(over); \ 2394 return true; \ 2395 } \ 2396 return false; \ 2397} 2398 2399GEN_MM_TRANS(vmand_mm) 2400GEN_MM_TRANS(vmnand_mm) 2401GEN_MM_TRANS(vmandnot_mm) 2402GEN_MM_TRANS(vmxor_mm) 2403GEN_MM_TRANS(vmor_mm) 2404GEN_MM_TRANS(vmnor_mm) 2405GEN_MM_TRANS(vmornot_mm) 2406GEN_MM_TRANS(vmxnor_mm) 2407 2408/* Vector mask population count vmpopc */ 2409static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) 2410{ 2411 if (vext_check_isa_ill(s)) { 2412 TCGv_ptr src2, mask; 2413 TCGv dst; 2414 TCGv_i32 desc; 2415 uint32_t data = 0; 2416 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2417 data = FIELD_DP32(data, VDATA, VM, a->vm); 2418 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2419 2420 mask = tcg_temp_new_ptr(); 2421 src2 = tcg_temp_new_ptr(); 2422 dst = tcg_temp_new(); 2423 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 2424 2425 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2426 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2427 2428 gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc); 2429 gen_set_gpr(a->rd, dst); 2430 2431 tcg_temp_free_ptr(mask); 2432 tcg_temp_free_ptr(src2); 2433 tcg_temp_free(dst); 2434 tcg_temp_free_i32(desc); 2435 return true; 2436 } 2437 return false; 2438} 2439 2440/* vmfirst find-first-set mask bit */ 2441static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) 2442{ 2443 if (vext_check_isa_ill(s)) { 2444 TCGv_ptr src2, mask; 2445 TCGv dst; 2446 TCGv_i32 desc; 2447 uint32_t data = 0; 2448 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2449 data = FIELD_DP32(data, VDATA, VM, a->vm); 2450 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2451 2452 mask = tcg_temp_new_ptr(); 2453 src2 = tcg_temp_new_ptr(); 2454 dst = tcg_temp_new(); 2455 desc = tcg_const_i32(simd_desc(0, s->vlen / 8, data)); 2456 2457 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2458 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2459 2460 gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc); 2461 gen_set_gpr(a->rd, dst); 2462 2463 tcg_temp_free_ptr(mask); 2464 tcg_temp_free_ptr(src2); 2465 tcg_temp_free(dst); 2466 tcg_temp_free_i32(desc); 2467 return true; 2468 } 2469 return false; 2470} 2471 2472/* vmsbf.m set-before-first mask bit */ 2473/* vmsif.m set-includ-first mask bit */ 2474/* vmsof.m set-only-first mask bit */ 2475#define GEN_M_TRANS(NAME) \ 2476static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2477{ \ 2478 if (vext_check_isa_ill(s)) { \ 2479 uint32_t data = 0; \ 2480 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2481 TCGLabel *over = gen_new_label(); \ 2482 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2483 \ 2484 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2485 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2486 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2487 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2488 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2489 cpu_env, 0, s->vlen / 8, data, fn); \ 2490 gen_set_label(over); \ 2491 return true; \ 2492 } \ 2493 return false; \ 2494} 2495 2496GEN_M_TRANS(vmsbf_m) 2497GEN_M_TRANS(vmsif_m) 2498GEN_M_TRANS(vmsof_m) 2499 2500/* Vector Iota Instruction */ 2501static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2502{ 2503 if (vext_check_isa_ill(s) && 2504 vext_check_reg(s, a->rd, false) && 2505 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) && 2506 (a->vm != 0 || a->rd != 0)) { 2507 uint32_t data = 0; 2508 TCGLabel *over = gen_new_label(); 2509 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2510 2511 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2512 data = FIELD_DP32(data, VDATA, VM, a->vm); 2513 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2514 static gen_helper_gvec_3_ptr * const fns[4] = { 2515 gen_helper_viota_m_b, gen_helper_viota_m_h, 2516 gen_helper_viota_m_w, gen_helper_viota_m_d, 2517 }; 2518 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2519 vreg_ofs(s, a->rs2), cpu_env, 0, 2520 s->vlen / 8, data, fns[s->sew]); 2521 gen_set_label(over); 2522 return true; 2523 } 2524 return false; 2525} 2526 2527/* Vector Element Index Instruction */ 2528static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 2529{ 2530 if (vext_check_isa_ill(s) && 2531 vext_check_reg(s, a->rd, false) && 2532 vext_check_overlap_mask(s, a->rd, a->vm, false)) { 2533 uint32_t data = 0; 2534 TCGLabel *over = gen_new_label(); 2535 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2536 2537 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2538 data = FIELD_DP32(data, VDATA, VM, a->vm); 2539 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2540 static gen_helper_gvec_2_ptr * const fns[4] = { 2541 gen_helper_vid_v_b, gen_helper_vid_v_h, 2542 gen_helper_vid_v_w, gen_helper_vid_v_d, 2543 }; 2544 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2545 cpu_env, 0, s->vlen / 8, data, fns[s->sew]); 2546 gen_set_label(over); 2547 return true; 2548 } 2549 return false; 2550} 2551 2552/* 2553 *** Vector Permutation Instructions 2554 */ 2555 2556/* Integer Extract Instruction */ 2557 2558static void load_element(TCGv_i64 dest, TCGv_ptr base, 2559 int ofs, int sew) 2560{ 2561 switch (sew) { 2562 case MO_8: 2563 tcg_gen_ld8u_i64(dest, base, ofs); 2564 break; 2565 case MO_16: 2566 tcg_gen_ld16u_i64(dest, base, ofs); 2567 break; 2568 case MO_32: 2569 tcg_gen_ld32u_i64(dest, base, ofs); 2570 break; 2571 case MO_64: 2572 tcg_gen_ld_i64(dest, base, ofs); 2573 break; 2574 default: 2575 g_assert_not_reached(); 2576 break; 2577 } 2578} 2579 2580/* offset of the idx element with base regsiter r */ 2581static uint32_t endian_ofs(DisasContext *s, int r, int idx) 2582{ 2583#ifdef HOST_WORDS_BIGENDIAN 2584 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 2585#else 2586 return vreg_ofs(s, r) + (idx << s->sew); 2587#endif 2588} 2589 2590/* adjust the index according to the endian */ 2591static void endian_adjust(TCGv_i32 ofs, int sew) 2592{ 2593#ifdef HOST_WORDS_BIGENDIAN 2594 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 2595#endif 2596} 2597 2598/* Load idx >= VLMAX ? 0 : vreg[idx] */ 2599static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 2600 int vreg, TCGv idx, int vlmax) 2601{ 2602 TCGv_i32 ofs = tcg_temp_new_i32(); 2603 TCGv_ptr base = tcg_temp_new_ptr(); 2604 TCGv_i64 t_idx = tcg_temp_new_i64(); 2605 TCGv_i64 t_vlmax, t_zero; 2606 2607 /* 2608 * Mask the index to the length so that we do 2609 * not produce an out-of-range load. 2610 */ 2611 tcg_gen_trunc_tl_i32(ofs, idx); 2612 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 2613 2614 /* Convert the index to an offset. */ 2615 endian_adjust(ofs, s->sew); 2616 tcg_gen_shli_i32(ofs, ofs, s->sew); 2617 2618 /* Convert the index to a pointer. */ 2619 tcg_gen_ext_i32_ptr(base, ofs); 2620 tcg_gen_add_ptr(base, base, cpu_env); 2621 2622 /* Perform the load. */ 2623 load_element(dest, base, 2624 vreg_ofs(s, vreg), s->sew); 2625 tcg_temp_free_ptr(base); 2626 tcg_temp_free_i32(ofs); 2627 2628 /* Flush out-of-range indexing to zero. */ 2629 t_vlmax = tcg_const_i64(vlmax); 2630 t_zero = tcg_const_i64(0); 2631 tcg_gen_extu_tl_i64(t_idx, idx); 2632 2633 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 2634 t_vlmax, dest, t_zero); 2635 2636 tcg_temp_free_i64(t_vlmax); 2637 tcg_temp_free_i64(t_zero); 2638 tcg_temp_free_i64(t_idx); 2639} 2640 2641static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 2642 int vreg, int idx) 2643{ 2644 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2645} 2646 2647static bool trans_vext_x_v(DisasContext *s, arg_r *a) 2648{ 2649 TCGv_i64 tmp = tcg_temp_new_i64(); 2650 TCGv dest = tcg_temp_new(); 2651 2652 if (a->rs1 == 0) { 2653 /* Special case vmv.x.s rd, vs2. */ 2654 vec_element_loadi(s, tmp, a->rs2, 0); 2655 } else { 2656 /* This instruction ignores LMUL and vector register groups */ 2657 int vlmax = s->vlen >> (3 + s->sew); 2658 vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); 2659 } 2660 tcg_gen_trunc_i64_tl(dest, tmp); 2661 gen_set_gpr(a->rd, dest); 2662 2663 tcg_temp_free(dest); 2664 tcg_temp_free_i64(tmp); 2665 return true; 2666} 2667 2668/* Integer Scalar Move Instruction */ 2669 2670static void store_element(TCGv_i64 val, TCGv_ptr base, 2671 int ofs, int sew) 2672{ 2673 switch (sew) { 2674 case MO_8: 2675 tcg_gen_st8_i64(val, base, ofs); 2676 break; 2677 case MO_16: 2678 tcg_gen_st16_i64(val, base, ofs); 2679 break; 2680 case MO_32: 2681 tcg_gen_st32_i64(val, base, ofs); 2682 break; 2683 case MO_64: 2684 tcg_gen_st_i64(val, base, ofs); 2685 break; 2686 default: 2687 g_assert_not_reached(); 2688 break; 2689 } 2690} 2691 2692/* 2693 * Store vreg[idx] = val. 2694 * The index must be in range of VLMAX. 2695 */ 2696static void vec_element_storei(DisasContext *s, int vreg, 2697 int idx, TCGv_i64 val) 2698{ 2699 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2700} 2701 2702/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 2703static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 2704{ 2705 if (vext_check_isa_ill(s)) { 2706 /* This instruction ignores LMUL and vector register groups */ 2707 int maxsz = s->vlen >> 3; 2708 TCGv_i64 t1; 2709 TCGLabel *over = gen_new_label(); 2710 2711 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2712 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); 2713 if (a->rs1 == 0) { 2714 goto done; 2715 } 2716 2717 t1 = tcg_temp_new_i64(); 2718 tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); 2719 vec_element_storei(s, a->rd, 0, t1); 2720 tcg_temp_free_i64(t1); 2721 done: 2722 gen_set_label(over); 2723 return true; 2724 } 2725 return false; 2726} 2727 2728/* Floating-Point Scalar Move Instructions */ 2729static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 2730{ 2731 if (!s->vill && has_ext(s, RVF) && 2732 (s->mstatus_fs != 0) && (s->sew != 0)) { 2733 unsigned int len = 8 << s->sew; 2734 2735 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); 2736 if (len < 64) { 2737 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 2738 MAKE_64BIT_MASK(len, 64 - len)); 2739 } 2740 2741 mark_fs_dirty(s); 2742 return true; 2743 } 2744 return false; 2745} 2746 2747/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 2748static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 2749{ 2750 if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { 2751 TCGv_i64 t1; 2752 /* The instructions ignore LMUL and vector register group. */ 2753 uint32_t vlmax = s->vlen >> 3; 2754 2755 /* if vl == 0, skip vector register write back */ 2756 TCGLabel *over = gen_new_label(); 2757 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2758 2759 /* zeroed all elements */ 2760 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); 2761 2762 /* NaN-box f[rs1] as necessary for SEW */ 2763 t1 = tcg_temp_new_i64(); 2764 if (s->sew == MO_64 && !has_ext(s, RVD)) { 2765 tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); 2766 } else { 2767 tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); 2768 } 2769 vec_element_storei(s, a->rd, 0, t1); 2770 tcg_temp_free_i64(t1); 2771 gen_set_label(over); 2772 return true; 2773 } 2774 return false; 2775} 2776 2777/* Vector Slide Instructions */ 2778static bool slideup_check(DisasContext *s, arg_rmrr *a) 2779{ 2780 return (vext_check_isa_ill(s) && 2781 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2782 vext_check_reg(s, a->rd, false) && 2783 vext_check_reg(s, a->rs2, false) && 2784 (a->rd != a->rs2)); 2785} 2786 2787GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 2788GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 2789GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check) 2790 2791GEN_OPIVX_TRANS(vslidedown_vx, opivx_check) 2792GEN_OPIVX_TRANS(vslide1down_vx, opivx_check) 2793GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check) 2794 2795/* Vector Register Gather Instruction */ 2796static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 2797{ 2798 return (vext_check_isa_ill(s) && 2799 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2800 vext_check_reg(s, a->rd, false) && 2801 vext_check_reg(s, a->rs1, false) && 2802 vext_check_reg(s, a->rs2, false) && 2803 (a->rd != a->rs2) && (a->rd != a->rs1)); 2804} 2805 2806GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 2807 2808static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 2809{ 2810 return (vext_check_isa_ill(s) && 2811 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2812 vext_check_reg(s, a->rd, false) && 2813 vext_check_reg(s, a->rs2, false) && 2814 (a->rd != a->rs2)); 2815} 2816 2817/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 2818static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 2819{ 2820 if (!vrgather_vx_check(s, a)) { 2821 return false; 2822 } 2823 2824 if (a->vm && s->vl_eq_vlmax) { 2825 int vlmax = s->vlen / s->mlen; 2826 TCGv_i64 dest = tcg_temp_new_i64(); 2827 2828 if (a->rs1 == 0) { 2829 vec_element_loadi(s, dest, a->rs2, 0); 2830 } else { 2831 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 2832 } 2833 2834 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2835 MAXSZ(s), MAXSZ(s), dest); 2836 tcg_temp_free_i64(dest); 2837 } else { 2838 static gen_helper_opivx * const fns[4] = { 2839 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2840 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2841 }; 2842 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 2843 } 2844 return true; 2845} 2846 2847/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 2848static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 2849{ 2850 if (!vrgather_vx_check(s, a)) { 2851 return false; 2852 } 2853 2854 if (a->vm && s->vl_eq_vlmax) { 2855 if (a->rs1 >= s->vlen / s->mlen) { 2856 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), 2857 MAXSZ(s), MAXSZ(s), 0); 2858 } else { 2859 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 2860 endian_ofs(s, a->rs2, a->rs1), 2861 MAXSZ(s), MAXSZ(s)); 2862 } 2863 } else { 2864 static gen_helper_opivx * const fns[4] = { 2865 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2866 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2867 }; 2868 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1); 2869 } 2870 return true; 2871} 2872 2873/* Vector Compress Instruction */ 2874static bool vcompress_vm_check(DisasContext *s, arg_r *a) 2875{ 2876 return (vext_check_isa_ill(s) && 2877 vext_check_reg(s, a->rd, false) && 2878 vext_check_reg(s, a->rs2, false) && 2879 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) && 2880 (a->rd != a->rs2)); 2881} 2882 2883static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 2884{ 2885 if (vcompress_vm_check(s, a)) { 2886 uint32_t data = 0; 2887 static gen_helper_gvec_4_ptr * const fns[4] = { 2888 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 2889 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 2890 }; 2891 TCGLabel *over = gen_new_label(); 2892 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2893 2894 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2895 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2896 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2897 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 2898 cpu_env, 0, s->vlen / 8, data, fns[s->sew]); 2899 gen_set_label(over); 2900 return true; 2901 } 2902 return false; 2903} 2904