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