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