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