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 } 708 709 switch (s->sew) { 710 case 0 ... 2: 711 assert(seq < ARRAY_SIZE(fnsw)); 712 fn = fnsw[seq]; 713 break; 714 case 3: 715 /* XLEN check done in amo_check(). */ 716 assert(seq < ARRAY_SIZE(fnsd)); 717 fn = fnsd[seq]; 718 break; 719 default: 720 g_assert_not_reached(); 721 } 722 723 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 724 data = FIELD_DP32(data, VDATA, VM, a->vm); 725 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 726 data = FIELD_DP32(data, VDATA, WD, a->wd); 727 return amo_trans(a->rd, a->rs1, a->rs2, data, fn, s); 728} 729/* 730 * There are two rules check here. 731 * 732 * 1. SEW must be at least as wide as the AMO memory element size. 733 * 734 * 2. If SEW is greater than XLEN, an illegal instruction exception is raised. 735 */ 736static bool amo_check(DisasContext *s, arg_rwdvm* a) 737{ 738 return (!s->vill && has_ext(s, RVA) && 739 (!a->wd || vext_check_overlap_mask(s, a->rd, a->vm, false)) && 740 vext_check_reg(s, a->rd, false) && 741 vext_check_reg(s, a->rs2, false) && 742 ((1 << s->sew) <= sizeof(target_ulong)) && 743 ((1 << s->sew) >= 4)); 744} 745 746static bool amo_check64(DisasContext *s, arg_rwdvm* a) 747{ 748 REQUIRE_64BIT(s); 749 return amo_check(s, a); 750} 751 752GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) 753GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check) 754GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check) 755GEN_VEXT_TRANS(vamoandw_v, 3, rwdvm, amo_op, amo_check) 756GEN_VEXT_TRANS(vamoorw_v, 4, rwdvm, amo_op, amo_check) 757GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check) 758GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check) 759GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check) 760GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check) 761GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64) 762GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64) 763GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64) 764GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64) 765GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64) 766GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64) 767GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64) 768GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64) 769GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64) 770 771/* 772 *** Vector Integer Arithmetic Instructions 773 */ 774#define MAXSZ(s) (s->vlen >> (3 - s->lmul)) 775 776static bool opivv_check(DisasContext *s, arg_rmrr *a) 777{ 778 return (vext_check_isa_ill(s) && 779 vext_check_overlap_mask(s, a->rd, a->vm, false) && 780 vext_check_reg(s, a->rd, false) && 781 vext_check_reg(s, a->rs2, false) && 782 vext_check_reg(s, a->rs1, false)); 783} 784 785typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 786 uint32_t, uint32_t, uint32_t); 787 788static inline bool 789do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 790 gen_helper_gvec_4_ptr *fn) 791{ 792 TCGLabel *over = gen_new_label(); 793 if (!opivv_check(s, a)) { 794 return false; 795 } 796 797 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 798 799 if (a->vm && s->vl_eq_vlmax) { 800 gvec_fn(s->sew, vreg_ofs(s, a->rd), 801 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 802 MAXSZ(s), MAXSZ(s)); 803 } else { 804 uint32_t data = 0; 805 806 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 807 data = FIELD_DP32(data, VDATA, VM, a->vm); 808 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 809 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 810 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 811 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 812 } 813 gen_set_label(over); 814 return true; 815} 816 817/* OPIVV with GVEC IR */ 818#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 819static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 820{ \ 821 static gen_helper_gvec_4_ptr * const fns[4] = { \ 822 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 823 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 824 }; \ 825 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 826} 827 828GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 829GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 830 831typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 832 TCGv_env, TCGv_i32); 833 834static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 835 gen_helper_opivx *fn, DisasContext *s) 836{ 837 TCGv_ptr dest, src2, mask; 838 TCGv src1; 839 TCGv_i32 desc; 840 uint32_t data = 0; 841 842 TCGLabel *over = gen_new_label(); 843 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 844 845 dest = tcg_temp_new_ptr(); 846 mask = tcg_temp_new_ptr(); 847 src2 = tcg_temp_new_ptr(); 848 src1 = get_gpr(s, rs1, EXT_NONE); 849 850 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 851 data = FIELD_DP32(data, VDATA, VM, vm); 852 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 853 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 854 855 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 856 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 857 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 858 859 fn(dest, mask, src1, src2, cpu_env, desc); 860 861 tcg_temp_free_ptr(dest); 862 tcg_temp_free_ptr(mask); 863 tcg_temp_free_ptr(src2); 864 gen_set_label(over); 865 return true; 866} 867 868static bool opivx_check(DisasContext *s, arg_rmrr *a) 869{ 870 return (vext_check_isa_ill(s) && 871 vext_check_overlap_mask(s, a->rd, a->vm, false) && 872 vext_check_reg(s, a->rd, false) && 873 vext_check_reg(s, a->rs2, false)); 874} 875 876typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 877 uint32_t, uint32_t); 878 879static inline bool 880do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 881 gen_helper_opivx *fn) 882{ 883 if (!opivx_check(s, a)) { 884 return false; 885 } 886 887 if (a->vm && s->vl_eq_vlmax) { 888 TCGv_i64 src1 = tcg_temp_new_i64(); 889 890 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 891 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 892 src1, MAXSZ(s), MAXSZ(s)); 893 894 tcg_temp_free_i64(src1); 895 return true; 896 } 897 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 898} 899 900/* OPIVX with GVEC IR */ 901#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 902static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 903{ \ 904 static gen_helper_opivx * const fns[4] = { \ 905 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 906 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 907 }; \ 908 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 909} 910 911GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 912GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 913 914static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 915{ 916 tcg_gen_vec_sub8_i64(d, b, a); 917} 918 919static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 920{ 921 tcg_gen_vec_sub16_i64(d, b, a); 922} 923 924static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 925{ 926 tcg_gen_sub_i32(ret, arg2, arg1); 927} 928 929static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 930{ 931 tcg_gen_sub_i64(ret, arg2, arg1); 932} 933 934static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 935{ 936 tcg_gen_sub_vec(vece, r, b, a); 937} 938 939static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 940 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 941{ 942 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 943 static const GVecGen2s rsub_op[4] = { 944 { .fni8 = gen_vec_rsub8_i64, 945 .fniv = gen_rsub_vec, 946 .fno = gen_helper_vec_rsubs8, 947 .opt_opc = vecop_list, 948 .vece = MO_8 }, 949 { .fni8 = gen_vec_rsub16_i64, 950 .fniv = gen_rsub_vec, 951 .fno = gen_helper_vec_rsubs16, 952 .opt_opc = vecop_list, 953 .vece = MO_16 }, 954 { .fni4 = gen_rsub_i32, 955 .fniv = gen_rsub_vec, 956 .fno = gen_helper_vec_rsubs32, 957 .opt_opc = vecop_list, 958 .vece = MO_32 }, 959 { .fni8 = gen_rsub_i64, 960 .fniv = gen_rsub_vec, 961 .fno = gen_helper_vec_rsubs64, 962 .opt_opc = vecop_list, 963 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 964 .vece = MO_64 }, 965 }; 966 967 tcg_debug_assert(vece <= MO_64); 968 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 969} 970 971GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 972 973static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 974 gen_helper_opivx *fn, DisasContext *s, int zx) 975{ 976 TCGv_ptr dest, src2, mask; 977 TCGv src1; 978 TCGv_i32 desc; 979 uint32_t data = 0; 980 981 TCGLabel *over = gen_new_label(); 982 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 983 984 dest = tcg_temp_new_ptr(); 985 mask = tcg_temp_new_ptr(); 986 src2 = tcg_temp_new_ptr(); 987 if (zx) { 988 src1 = tcg_constant_tl(imm); 989 } else { 990 src1 = tcg_constant_tl(sextract64(imm, 0, 5)); 991 } 992 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 993 data = FIELD_DP32(data, VDATA, VM, vm); 994 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 995 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 996 997 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 998 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 999 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1000 1001 fn(dest, mask, src1, src2, cpu_env, desc); 1002 1003 tcg_temp_free_ptr(dest); 1004 tcg_temp_free_ptr(mask); 1005 tcg_temp_free_ptr(src2); 1006 gen_set_label(over); 1007 return true; 1008} 1009 1010typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1011 uint32_t, uint32_t); 1012 1013static inline bool 1014do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1015 gen_helper_opivx *fn, int zx) 1016{ 1017 if (!opivx_check(s, a)) { 1018 return false; 1019 } 1020 1021 if (a->vm && s->vl_eq_vlmax) { 1022 if (zx) { 1023 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1024 extract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); 1025 } else { 1026 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1027 sextract64(a->rs1, 0, 5), MAXSZ(s), MAXSZ(s)); 1028 } 1029 } else { 1030 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, zx); 1031 } 1032 return true; 1033} 1034 1035/* OPIVI with GVEC IR */ 1036#define GEN_OPIVI_GVEC_TRANS(NAME, ZX, OPIVX, SUF) \ 1037static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1038{ \ 1039 static gen_helper_opivx * const fns[4] = { \ 1040 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1041 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1042 }; \ 1043 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1044 fns[s->sew], ZX); \ 1045} 1046 1047GEN_OPIVI_GVEC_TRANS(vadd_vi, 0, vadd_vx, addi) 1048 1049static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1050 int64_t c, uint32_t oprsz, uint32_t maxsz) 1051{ 1052 TCGv_i64 tmp = tcg_constant_i64(c); 1053 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1054} 1055 1056GEN_OPIVI_GVEC_TRANS(vrsub_vi, 0, vrsub_vx, rsubi) 1057 1058/* Vector Widening Integer Add/Subtract */ 1059 1060/* OPIVV with WIDEN */ 1061static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1062{ 1063 return (vext_check_isa_ill(s) && 1064 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1065 vext_check_reg(s, a->rd, true) && 1066 vext_check_reg(s, a->rs2, false) && 1067 vext_check_reg(s, a->rs1, false) && 1068 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1069 1 << s->lmul) && 1070 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1071 1 << s->lmul) && 1072 (s->lmul < 0x3) && (s->sew < 0x3)); 1073} 1074 1075static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1076 gen_helper_gvec_4_ptr *fn, 1077 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1078{ 1079 if (checkfn(s, a)) { 1080 uint32_t data = 0; 1081 TCGLabel *over = gen_new_label(); 1082 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1083 1084 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 1085 data = FIELD_DP32(data, VDATA, VM, a->vm); 1086 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1087 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1088 vreg_ofs(s, a->rs1), 1089 vreg_ofs(s, a->rs2), 1090 cpu_env, s->vlen / 8, s->vlen / 8, 1091 data, fn); 1092 gen_set_label(over); 1093 return true; 1094 } 1095 return false; 1096} 1097 1098#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1099static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1100{ \ 1101 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1102 gen_helper_##NAME##_b, \ 1103 gen_helper_##NAME##_h, \ 1104 gen_helper_##NAME##_w \ 1105 }; \ 1106 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1107} 1108 1109GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1110GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1111GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1112GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1113 1114/* OPIVX with WIDEN */ 1115static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1116{ 1117 return (vext_check_isa_ill(s) && 1118 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1119 vext_check_reg(s, a->rd, true) && 1120 vext_check_reg(s, a->rs2, false) && 1121 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1122 1 << s->lmul) && 1123 (s->lmul < 0x3) && (s->sew < 0x3)); 1124} 1125 1126static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, 1127 gen_helper_opivx *fn) 1128{ 1129 if (opivx_widen_check(s, a)) { 1130 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1131 } 1132 return false; 1133} 1134 1135#define GEN_OPIVX_WIDEN_TRANS(NAME) \ 1136static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1137{ \ 1138 static gen_helper_opivx * const fns[3] = { \ 1139 gen_helper_##NAME##_b, \ 1140 gen_helper_##NAME##_h, \ 1141 gen_helper_##NAME##_w \ 1142 }; \ 1143 return do_opivx_widen(s, a, fns[s->sew]); \ 1144} 1145 1146GEN_OPIVX_WIDEN_TRANS(vwaddu_vx) 1147GEN_OPIVX_WIDEN_TRANS(vwadd_vx) 1148GEN_OPIVX_WIDEN_TRANS(vwsubu_vx) 1149GEN_OPIVX_WIDEN_TRANS(vwsub_vx) 1150 1151/* WIDEN OPIVV with WIDEN */ 1152static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1153{ 1154 return (vext_check_isa_ill(s) && 1155 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1156 vext_check_reg(s, a->rd, true) && 1157 vext_check_reg(s, a->rs2, true) && 1158 vext_check_reg(s, a->rs1, false) && 1159 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1160 1 << s->lmul) && 1161 (s->lmul < 0x3) && (s->sew < 0x3)); 1162} 1163 1164static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1165 gen_helper_gvec_4_ptr *fn) 1166{ 1167 if (opiwv_widen_check(s, a)) { 1168 uint32_t data = 0; 1169 TCGLabel *over = gen_new_label(); 1170 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1171 1172 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 1173 data = FIELD_DP32(data, VDATA, VM, a->vm); 1174 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1175 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1176 vreg_ofs(s, a->rs1), 1177 vreg_ofs(s, a->rs2), 1178 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1179 gen_set_label(over); 1180 return true; 1181 } 1182 return false; 1183} 1184 1185#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1186static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1187{ \ 1188 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1189 gen_helper_##NAME##_b, \ 1190 gen_helper_##NAME##_h, \ 1191 gen_helper_##NAME##_w \ 1192 }; \ 1193 return do_opiwv_widen(s, a, fns[s->sew]); \ 1194} 1195 1196GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1197GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1198GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1199GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1200 1201/* WIDEN OPIVX with WIDEN */ 1202static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1203{ 1204 return (vext_check_isa_ill(s) && 1205 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1206 vext_check_reg(s, a->rd, true) && 1207 vext_check_reg(s, a->rs2, true) && 1208 (s->lmul < 0x3) && (s->sew < 0x3)); 1209} 1210 1211static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1212 gen_helper_opivx *fn) 1213{ 1214 if (opiwx_widen_check(s, a)) { 1215 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1216 } 1217 return false; 1218} 1219 1220#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1221static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1222{ \ 1223 static gen_helper_opivx * const fns[3] = { \ 1224 gen_helper_##NAME##_b, \ 1225 gen_helper_##NAME##_h, \ 1226 gen_helper_##NAME##_w \ 1227 }; \ 1228 return do_opiwx_widen(s, a, fns[s->sew]); \ 1229} 1230 1231GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1232GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1233GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1234GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1235 1236/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1237/* OPIVV without GVEC IR */ 1238#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1239static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1240{ \ 1241 if (CHECK(s, a)) { \ 1242 uint32_t data = 0; \ 1243 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1244 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1245 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1246 }; \ 1247 TCGLabel *over = gen_new_label(); \ 1248 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1249 \ 1250 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1251 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1252 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1253 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1254 vreg_ofs(s, a->rs1), \ 1255 vreg_ofs(s, a->rs2), cpu_env, \ 1256 s->vlen / 8, s->vlen / 8, data, \ 1257 fns[s->sew]); \ 1258 gen_set_label(over); \ 1259 return true; \ 1260 } \ 1261 return false; \ 1262} 1263 1264/* 1265 * For vadc and vsbc, an illegal instruction exception is raised if the 1266 * destination vector register is v0 and LMUL > 1. (Section 12.3) 1267 */ 1268static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1269{ 1270 return (vext_check_isa_ill(s) && 1271 vext_check_reg(s, a->rd, false) && 1272 vext_check_reg(s, a->rs2, false) && 1273 vext_check_reg(s, a->rs1, false) && 1274 ((a->rd != 0) || (s->lmul == 0))); 1275} 1276 1277GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1278GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1279 1280/* 1281 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1282 * destination vector register overlaps a source vector register group. 1283 */ 1284static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1285{ 1286 return (vext_check_isa_ill(s) && 1287 vext_check_reg(s, a->rs2, false) && 1288 vext_check_reg(s, a->rs1, false) && 1289 vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1290 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1291} 1292 1293GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1294GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1295 1296static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1297{ 1298 return (vext_check_isa_ill(s) && 1299 vext_check_reg(s, a->rd, false) && 1300 vext_check_reg(s, a->rs2, false) && 1301 ((a->rd != 0) || (s->lmul == 0))); 1302} 1303 1304/* OPIVX without GVEC IR */ 1305#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1306static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1307{ \ 1308 if (CHECK(s, a)) { \ 1309 static gen_helper_opivx * const fns[4] = { \ 1310 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1311 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1312 }; \ 1313 \ 1314 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1315 } \ 1316 return false; \ 1317} 1318 1319GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1320GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1321 1322static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1323{ 1324 return (vext_check_isa_ill(s) && 1325 vext_check_reg(s, a->rs2, false) && 1326 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)); 1327} 1328 1329GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1330GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1331 1332/* OPIVI without GVEC IR */ 1333#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \ 1334static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1335{ \ 1336 if (CHECK(s, a)) { \ 1337 static gen_helper_opivx * const fns[4] = { \ 1338 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1339 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1340 }; \ 1341 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1342 fns[s->sew], s, ZX); \ 1343 } \ 1344 return false; \ 1345} 1346 1347GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check) 1348GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check) 1349 1350/* Vector Bitwise Logical Instructions */ 1351GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1352GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1353GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1354GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1355GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1356GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1357GEN_OPIVI_GVEC_TRANS(vand_vi, 0, vand_vx, andi) 1358GEN_OPIVI_GVEC_TRANS(vor_vi, 0, vor_vx, ori) 1359GEN_OPIVI_GVEC_TRANS(vxor_vi, 0, vxor_vx, xori) 1360 1361/* Vector Single-Width Bit Shift Instructions */ 1362GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1363GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1364GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1365 1366typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1367 uint32_t, uint32_t); 1368 1369static inline bool 1370do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1371 gen_helper_opivx *fn) 1372{ 1373 if (!opivx_check(s, a)) { 1374 return false; 1375 } 1376 1377 if (a->vm && s->vl_eq_vlmax) { 1378 TCGv_i32 src1 = tcg_temp_new_i32(); 1379 1380 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1381 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1382 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1383 src1, MAXSZ(s), MAXSZ(s)); 1384 1385 tcg_temp_free_i32(src1); 1386 return true; 1387 } 1388 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1389} 1390 1391#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1392static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1393{ \ 1394 static gen_helper_opivx * const fns[4] = { \ 1395 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1396 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1397 }; \ 1398 \ 1399 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1400} 1401 1402GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1403GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1404GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1405 1406GEN_OPIVI_GVEC_TRANS(vsll_vi, 1, vsll_vx, shli) 1407GEN_OPIVI_GVEC_TRANS(vsrl_vi, 1, vsrl_vx, shri) 1408GEN_OPIVI_GVEC_TRANS(vsra_vi, 1, vsra_vx, sari) 1409 1410/* Vector Narrowing Integer Right Shift Instructions */ 1411static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) 1412{ 1413 return (vext_check_isa_ill(s) && 1414 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1415 vext_check_reg(s, a->rd, false) && 1416 vext_check_reg(s, a->rs2, true) && 1417 vext_check_reg(s, a->rs1, false) && 1418 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1419 2 << s->lmul) && 1420 (s->lmul < 0x3) && (s->sew < 0x3)); 1421} 1422 1423/* OPIVV with NARROW */ 1424#define GEN_OPIVV_NARROW_TRANS(NAME) \ 1425static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1426{ \ 1427 if (opivv_narrow_check(s, a)) { \ 1428 uint32_t data = 0; \ 1429 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1430 gen_helper_##NAME##_b, \ 1431 gen_helper_##NAME##_h, \ 1432 gen_helper_##NAME##_w, \ 1433 }; \ 1434 TCGLabel *over = gen_new_label(); \ 1435 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1436 \ 1437 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1438 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1439 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1440 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1441 vreg_ofs(s, a->rs1), \ 1442 vreg_ofs(s, a->rs2), cpu_env, \ 1443 s->vlen / 8, s->vlen / 8, data, \ 1444 fns[s->sew]); \ 1445 gen_set_label(over); \ 1446 return true; \ 1447 } \ 1448 return false; \ 1449} 1450GEN_OPIVV_NARROW_TRANS(vnsra_vv) 1451GEN_OPIVV_NARROW_TRANS(vnsrl_vv) 1452 1453static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) 1454{ 1455 return (vext_check_isa_ill(s) && 1456 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1457 vext_check_reg(s, a->rd, false) && 1458 vext_check_reg(s, a->rs2, true) && 1459 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1460 2 << s->lmul) && 1461 (s->lmul < 0x3) && (s->sew < 0x3)); 1462} 1463 1464/* OPIVX with NARROW */ 1465#define GEN_OPIVX_NARROW_TRANS(NAME) \ 1466static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1467{ \ 1468 if (opivx_narrow_check(s, a)) { \ 1469 static gen_helper_opivx * const fns[3] = { \ 1470 gen_helper_##NAME##_b, \ 1471 gen_helper_##NAME##_h, \ 1472 gen_helper_##NAME##_w, \ 1473 }; \ 1474 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1475 } \ 1476 return false; \ 1477} 1478 1479GEN_OPIVX_NARROW_TRANS(vnsra_vx) 1480GEN_OPIVX_NARROW_TRANS(vnsrl_vx) 1481 1482/* OPIVI with NARROW */ 1483#define GEN_OPIVI_NARROW_TRANS(NAME, ZX, OPIVX) \ 1484static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1485{ \ 1486 if (opivx_narrow_check(s, a)) { \ 1487 static gen_helper_opivx * const fns[3] = { \ 1488 gen_helper_##OPIVX##_b, \ 1489 gen_helper_##OPIVX##_h, \ 1490 gen_helper_##OPIVX##_w, \ 1491 }; \ 1492 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1493 fns[s->sew], s, ZX); \ 1494 } \ 1495 return false; \ 1496} 1497 1498GEN_OPIVI_NARROW_TRANS(vnsra_vi, 1, vnsra_vx) 1499GEN_OPIVI_NARROW_TRANS(vnsrl_vi, 1, vnsrl_vx) 1500 1501/* Vector Integer Comparison Instructions */ 1502/* 1503 * For all comparison instructions, an illegal instruction exception is raised 1504 * if the destination vector register overlaps a source vector register group 1505 * and LMUL > 1. 1506 */ 1507static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1508{ 1509 return (vext_check_isa_ill(s) && 1510 vext_check_reg(s, a->rs2, false) && 1511 vext_check_reg(s, a->rs1, false) && 1512 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 1513 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 1514 (s->lmul == 0))); 1515} 1516GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1517GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1518GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1519GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1520GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1521GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1522 1523static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1524{ 1525 return (vext_check_isa_ill(s) && 1526 vext_check_reg(s, a->rs2, false) && 1527 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 1528 (s->lmul == 0))); 1529} 1530 1531GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1532GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1533GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1534GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1535GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1536GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1537GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1538GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1539 1540GEN_OPIVI_TRANS(vmseq_vi, 0, vmseq_vx, opivx_cmp_check) 1541GEN_OPIVI_TRANS(vmsne_vi, 0, vmsne_vx, opivx_cmp_check) 1542GEN_OPIVI_TRANS(vmsleu_vi, 1, vmsleu_vx, opivx_cmp_check) 1543GEN_OPIVI_TRANS(vmsle_vi, 0, vmsle_vx, opivx_cmp_check) 1544GEN_OPIVI_TRANS(vmsgtu_vi, 1, vmsgtu_vx, opivx_cmp_check) 1545GEN_OPIVI_TRANS(vmsgt_vi, 0, vmsgt_vx, opivx_cmp_check) 1546 1547/* Vector Integer Min/Max Instructions */ 1548GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1549GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1550GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1551GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1552GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1553GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1554GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1555GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1556 1557/* Vector Single-Width Integer Multiply Instructions */ 1558GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1559GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1560GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1561GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1562GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1563GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1564GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1565GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1566 1567/* Vector Integer Divide Instructions */ 1568GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1569GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1570GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1571GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1572GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1573GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1574GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1575GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1576 1577/* Vector Widening Integer Multiply Instructions */ 1578GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1579GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1580GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1581GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1582GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1583GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1584 1585/* Vector Single-Width Integer Multiply-Add Instructions */ 1586GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1587GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1588GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1589GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1590GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1591GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1592GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1593GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1594 1595/* Vector Widening Integer Multiply-Add Instructions */ 1596GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1597GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1598GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1599GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1600GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1601GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1602GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1603 1604/* Vector Integer Merge and Move Instructions */ 1605static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1606{ 1607 if (vext_check_isa_ill(s) && 1608 vext_check_reg(s, a->rd, false) && 1609 vext_check_reg(s, a->rs1, false)) { 1610 1611 if (s->vl_eq_vlmax) { 1612 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1613 vreg_ofs(s, a->rs1), 1614 MAXSZ(s), MAXSZ(s)); 1615 } else { 1616 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1617 static gen_helper_gvec_2_ptr * const fns[4] = { 1618 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1619 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1620 }; 1621 TCGLabel *over = gen_new_label(); 1622 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1623 1624 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1625 cpu_env, s->vlen / 8, s->vlen / 8, data, 1626 fns[s->sew]); 1627 gen_set_label(over); 1628 } 1629 return true; 1630 } 1631 return false; 1632} 1633 1634typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1635static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1636{ 1637 if (vext_check_isa_ill(s) && 1638 vext_check_reg(s, a->rd, false)) { 1639 1640 TCGv s1; 1641 TCGLabel *over = gen_new_label(); 1642 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1643 1644 s1 = get_gpr(s, a->rs1, EXT_SIGN); 1645 1646 if (s->vl_eq_vlmax) { 1647 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 1648 MAXSZ(s), MAXSZ(s), s1); 1649 } else { 1650 TCGv_i32 desc; 1651 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 1652 TCGv_ptr dest = tcg_temp_new_ptr(); 1653 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1654 static gen_helper_vmv_vx * const fns[4] = { 1655 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1656 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1657 }; 1658 1659 tcg_gen_ext_tl_i64(s1_i64, s1); 1660 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1661 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1662 fns[s->sew](dest, s1_i64, cpu_env, desc); 1663 1664 tcg_temp_free_ptr(dest); 1665 tcg_temp_free_i64(s1_i64); 1666 } 1667 1668 gen_set_label(over); 1669 return true; 1670 } 1671 return false; 1672} 1673 1674static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 1675{ 1676 if (vext_check_isa_ill(s) && 1677 vext_check_reg(s, a->rd, false)) { 1678 1679 int64_t simm = sextract64(a->rs1, 0, 5); 1680 if (s->vl_eq_vlmax) { 1681 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 1682 MAXSZ(s), MAXSZ(s), simm); 1683 } else { 1684 TCGv_i32 desc; 1685 TCGv_i64 s1; 1686 TCGv_ptr dest; 1687 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1688 static gen_helper_vmv_vx * const fns[4] = { 1689 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1690 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1691 }; 1692 TCGLabel *over = gen_new_label(); 1693 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1694 1695 s1 = tcg_constant_i64(simm); 1696 dest = tcg_temp_new_ptr(); 1697 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1698 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1699 fns[s->sew](dest, s1, cpu_env, desc); 1700 1701 tcg_temp_free_ptr(dest); 1702 gen_set_label(over); 1703 } 1704 return true; 1705 } 1706 return false; 1707} 1708 1709GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 1710GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 1711GEN_OPIVI_TRANS(vmerge_vim, 0, vmerge_vxm, opivx_vadc_check) 1712 1713/* 1714 *** Vector Fixed-Point Arithmetic Instructions 1715 */ 1716 1717/* Vector Single-Width Saturating Add and Subtract */ 1718GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 1719GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 1720GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 1721GEN_OPIVV_TRANS(vssub_vv, opivv_check) 1722GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 1723GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 1724GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 1725GEN_OPIVX_TRANS(vssub_vx, opivx_check) 1726GEN_OPIVI_TRANS(vsaddu_vi, 1, vsaddu_vx, opivx_check) 1727GEN_OPIVI_TRANS(vsadd_vi, 0, vsadd_vx, opivx_check) 1728 1729/* Vector Single-Width Averaging Add and Subtract */ 1730GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 1731GEN_OPIVV_TRANS(vasub_vv, opivv_check) 1732GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 1733GEN_OPIVX_TRANS(vasub_vx, opivx_check) 1734GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) 1735 1736/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 1737GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 1738GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 1739 1740/* Vector Widening Saturating Scaled Multiply-Add */ 1741GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) 1742GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) 1743GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) 1744GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) 1745GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) 1746GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) 1747GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) 1748 1749/* Vector Single-Width Scaling Shift Instructions */ 1750GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 1751GEN_OPIVV_TRANS(vssra_vv, opivv_check) 1752GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 1753GEN_OPIVX_TRANS(vssra_vx, opivx_check) 1754GEN_OPIVI_TRANS(vssrl_vi, 1, vssrl_vx, opivx_check) 1755GEN_OPIVI_TRANS(vssra_vi, 0, vssra_vx, opivx_check) 1756 1757/* Vector Narrowing Fixed-Point Clip Instructions */ 1758GEN_OPIVV_NARROW_TRANS(vnclipu_vv) 1759GEN_OPIVV_NARROW_TRANS(vnclip_vv) 1760GEN_OPIVX_NARROW_TRANS(vnclipu_vx) 1761GEN_OPIVX_NARROW_TRANS(vnclip_vx) 1762GEN_OPIVI_NARROW_TRANS(vnclipu_vi, 1, vnclipu_vx) 1763GEN_OPIVI_NARROW_TRANS(vnclip_vi, 1, vnclip_vx) 1764 1765/* 1766 *** Vector Float Point Arithmetic Instructions 1767 */ 1768/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 1769 1770/* 1771 * If the current SEW does not correspond to a supported IEEE floating-point 1772 * type, an illegal instruction exception is raised. 1773 */ 1774static bool opfvv_check(DisasContext *s, arg_rmrr *a) 1775{ 1776 return (vext_check_isa_ill(s) && 1777 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1778 vext_check_reg(s, a->rd, false) && 1779 vext_check_reg(s, a->rs2, false) && 1780 vext_check_reg(s, a->rs1, false) && 1781 (s->sew != 0)); 1782} 1783 1784/* OPFVV without GVEC IR */ 1785#define GEN_OPFVV_TRANS(NAME, CHECK) \ 1786static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1787{ \ 1788 if (CHECK(s, a)) { \ 1789 uint32_t data = 0; \ 1790 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1791 gen_helper_##NAME##_h, \ 1792 gen_helper_##NAME##_w, \ 1793 gen_helper_##NAME##_d, \ 1794 }; \ 1795 TCGLabel *over = gen_new_label(); \ 1796 gen_set_rm(s, 7); \ 1797 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1798 \ 1799 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1800 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1801 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1802 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1803 vreg_ofs(s, a->rs1), \ 1804 vreg_ofs(s, a->rs2), cpu_env, \ 1805 s->vlen / 8, s->vlen / 8, data, \ 1806 fns[s->sew - 1]); \ 1807 gen_set_label(over); \ 1808 return true; \ 1809 } \ 1810 return false; \ 1811} 1812GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 1813GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 1814 1815typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 1816 TCGv_env, TCGv_i32); 1817 1818static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 1819 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 1820{ 1821 TCGv_ptr dest, src2, mask; 1822 TCGv_i32 desc; 1823 1824 TCGLabel *over = gen_new_label(); 1825 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1826 1827 dest = tcg_temp_new_ptr(); 1828 mask = tcg_temp_new_ptr(); 1829 src2 = tcg_temp_new_ptr(); 1830 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1831 1832 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1833 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1834 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1835 1836 fn(dest, mask, cpu_fpr[rs1], src2, cpu_env, desc); 1837 1838 tcg_temp_free_ptr(dest); 1839 tcg_temp_free_ptr(mask); 1840 tcg_temp_free_ptr(src2); 1841 gen_set_label(over); 1842 return true; 1843} 1844 1845static bool opfvf_check(DisasContext *s, arg_rmrr *a) 1846{ 1847/* 1848 * If the current SEW does not correspond to a supported IEEE floating-point 1849 * type, an illegal instruction exception is raised 1850 */ 1851 return (vext_check_isa_ill(s) && 1852 vext_check_overlap_mask(s, a->rd, a->vm, false) && 1853 vext_check_reg(s, a->rd, false) && 1854 vext_check_reg(s, a->rs2, false) && 1855 (s->sew != 0)); 1856} 1857 1858/* OPFVF without GVEC IR */ 1859#define GEN_OPFVF_TRANS(NAME, CHECK) \ 1860static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1861{ \ 1862 if (CHECK(s, a)) { \ 1863 uint32_t data = 0; \ 1864 static gen_helper_opfvf *const fns[3] = { \ 1865 gen_helper_##NAME##_h, \ 1866 gen_helper_##NAME##_w, \ 1867 gen_helper_##NAME##_d, \ 1868 }; \ 1869 gen_set_rm(s, 7); \ 1870 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1871 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1872 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1873 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1874 fns[s->sew - 1], s); \ 1875 } \ 1876 return false; \ 1877} 1878 1879GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 1880GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 1881GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 1882 1883/* Vector Widening Floating-Point Add/Subtract Instructions */ 1884static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 1885{ 1886 return (vext_check_isa_ill(s) && 1887 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1888 vext_check_reg(s, a->rd, true) && 1889 vext_check_reg(s, a->rs2, false) && 1890 vext_check_reg(s, a->rs1, false) && 1891 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1892 1 << s->lmul) && 1893 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1894 1 << s->lmul) && 1895 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1896} 1897 1898/* OPFVV with WIDEN */ 1899#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 1900static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1901{ \ 1902 if (CHECK(s, a)) { \ 1903 uint32_t data = 0; \ 1904 static gen_helper_gvec_4_ptr * const fns[2] = { \ 1905 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1906 }; \ 1907 TCGLabel *over = gen_new_label(); \ 1908 gen_set_rm(s, 7); \ 1909 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1910 \ 1911 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1912 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1913 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1914 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1915 vreg_ofs(s, a->rs1), \ 1916 vreg_ofs(s, a->rs2), cpu_env, \ 1917 s->vlen / 8, s->vlen / 8, data, \ 1918 fns[s->sew - 1]); \ 1919 gen_set_label(over); \ 1920 return true; \ 1921 } \ 1922 return false; \ 1923} 1924 1925GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 1926GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 1927 1928static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 1929{ 1930 return (vext_check_isa_ill(s) && 1931 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1932 vext_check_reg(s, a->rd, true) && 1933 vext_check_reg(s, a->rs2, false) && 1934 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 1935 1 << s->lmul) && 1936 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1937} 1938 1939/* OPFVF with WIDEN */ 1940#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 1941static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1942{ \ 1943 if (opfvf_widen_check(s, a)) { \ 1944 uint32_t data = 0; \ 1945 static gen_helper_opfvf *const fns[2] = { \ 1946 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1947 }; \ 1948 gen_set_rm(s, 7); \ 1949 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1950 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1951 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1952 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 1953 fns[s->sew - 1], s); \ 1954 } \ 1955 return false; \ 1956} 1957 1958GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 1959GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 1960 1961static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 1962{ 1963 return (vext_check_isa_ill(s) && 1964 vext_check_overlap_mask(s, a->rd, a->vm, true) && 1965 vext_check_reg(s, a->rd, true) && 1966 vext_check_reg(s, a->rs2, true) && 1967 vext_check_reg(s, a->rs1, false) && 1968 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs1, 1969 1 << s->lmul) && 1970 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 1971} 1972 1973/* WIDEN OPFVV with WIDEN */ 1974#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 1975static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1976{ \ 1977 if (opfwv_widen_check(s, a)) { \ 1978 uint32_t data = 0; \ 1979 static gen_helper_gvec_4_ptr * const fns[2] = { \ 1980 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 1981 }; \ 1982 TCGLabel *over = gen_new_label(); \ 1983 gen_set_rm(s, 7); \ 1984 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1985 \ 1986 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 1987 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1988 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1989 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1990 vreg_ofs(s, a->rs1), \ 1991 vreg_ofs(s, a->rs2), cpu_env, \ 1992 s->vlen / 8, s->vlen / 8, data, \ 1993 fns[s->sew - 1]); \ 1994 gen_set_label(over); \ 1995 return true; \ 1996 } \ 1997 return false; \ 1998} 1999 2000GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2001GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2002 2003static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2004{ 2005 return (vext_check_isa_ill(s) && 2006 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2007 vext_check_reg(s, a->rd, true) && 2008 vext_check_reg(s, a->rs2, true) && 2009 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2010} 2011 2012/* WIDEN OPFVF with WIDEN */ 2013#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2014static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2015{ \ 2016 if (opfwf_widen_check(s, a)) { \ 2017 uint32_t data = 0; \ 2018 static gen_helper_opfvf *const fns[2] = { \ 2019 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2020 }; \ 2021 gen_set_rm(s, 7); \ 2022 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2023 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2024 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2025 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2026 fns[s->sew - 1], s); \ 2027 } \ 2028 return false; \ 2029} 2030 2031GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2032GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2033 2034/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2035GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2036GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2037GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2038GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2039GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2040 2041/* Vector Widening Floating-Point Multiply */ 2042GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2043GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2044 2045/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2046GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2047GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2048GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2049GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2050GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2051GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2052GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2053GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2054GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2055GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2056GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2057GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2058GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2059GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2060GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2061GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2062 2063/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2064GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2065GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2066GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2067GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2068GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2069GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2070GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2071GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2072 2073/* Vector Floating-Point Square-Root Instruction */ 2074 2075/* 2076 * If the current SEW does not correspond to a supported IEEE floating-point 2077 * type, an illegal instruction exception is raised 2078 */ 2079static bool opfv_check(DisasContext *s, arg_rmr *a) 2080{ 2081 return (vext_check_isa_ill(s) && 2082 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2083 vext_check_reg(s, a->rd, false) && 2084 vext_check_reg(s, a->rs2, false) && 2085 (s->sew != 0)); 2086} 2087 2088#define GEN_OPFV_TRANS(NAME, CHECK) \ 2089static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2090{ \ 2091 if (CHECK(s, a)) { \ 2092 uint32_t data = 0; \ 2093 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2094 gen_helper_##NAME##_h, \ 2095 gen_helper_##NAME##_w, \ 2096 gen_helper_##NAME##_d, \ 2097 }; \ 2098 TCGLabel *over = gen_new_label(); \ 2099 gen_set_rm(s, 7); \ 2100 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2101 \ 2102 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2103 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2104 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2105 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2106 vreg_ofs(s, a->rs2), cpu_env, \ 2107 s->vlen / 8, s->vlen / 8, data, \ 2108 fns[s->sew - 1]); \ 2109 gen_set_label(over); \ 2110 return true; \ 2111 } \ 2112 return false; \ 2113} 2114 2115GEN_OPFV_TRANS(vfsqrt_v, opfv_check) 2116 2117/* Vector Floating-Point MIN/MAX Instructions */ 2118GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2119GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2120GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2121GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2122 2123/* Vector Floating-Point Sign-Injection Instructions */ 2124GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2125GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2126GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2127GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2128GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2129GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2130 2131/* Vector Floating-Point Compare Instructions */ 2132static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2133{ 2134 return (vext_check_isa_ill(s) && 2135 vext_check_reg(s, a->rs2, false) && 2136 vext_check_reg(s, a->rs1, false) && 2137 (s->sew != 0) && 2138 ((vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) && 2139 vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul)) || 2140 (s->lmul == 0))); 2141} 2142 2143GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2144GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2145GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2146GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2147GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) 2148 2149static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2150{ 2151 return (vext_check_isa_ill(s) && 2152 vext_check_reg(s, a->rs2, false) && 2153 (s->sew != 0) && 2154 (vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul) || 2155 (s->lmul == 0))); 2156} 2157 2158GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2159GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2160GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2161GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2162GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2163GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2164GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) 2165 2166/* Vector Floating-Point Classify Instruction */ 2167GEN_OPFV_TRANS(vfclass_v, opfv_check) 2168 2169/* Vector Floating-Point Merge Instruction */ 2170GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2171 2172static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2173{ 2174 if (vext_check_isa_ill(s) && 2175 vext_check_reg(s, a->rd, false) && 2176 (s->sew != 0)) { 2177 2178 if (s->vl_eq_vlmax) { 2179 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2180 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); 2181 } else { 2182 TCGv_ptr dest; 2183 TCGv_i32 desc; 2184 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2185 static gen_helper_vmv_vx * const fns[3] = { 2186 gen_helper_vmv_v_x_h, 2187 gen_helper_vmv_v_x_w, 2188 gen_helper_vmv_v_x_d, 2189 }; 2190 TCGLabel *over = gen_new_label(); 2191 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2192 2193 dest = tcg_temp_new_ptr(); 2194 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2195 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2196 fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); 2197 2198 tcg_temp_free_ptr(dest); 2199 gen_set_label(over); 2200 } 2201 return true; 2202 } 2203 return false; 2204} 2205 2206/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2207GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) 2208GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) 2209GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) 2210GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) 2211 2212/* Widening Floating-Point/Integer Type-Convert Instructions */ 2213 2214/* 2215 * If the current SEW does not correspond to a supported IEEE floating-point 2216 * type, an illegal instruction exception is raised 2217 */ 2218static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2219{ 2220 return (vext_check_isa_ill(s) && 2221 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2222 vext_check_reg(s, a->rd, true) && 2223 vext_check_reg(s, a->rs2, false) && 2224 vext_check_overlap_group(a->rd, 2 << s->lmul, a->rs2, 2225 1 << s->lmul) && 2226 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2227} 2228 2229#define GEN_OPFV_WIDEN_TRANS(NAME) \ 2230static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2231{ \ 2232 if (opfv_widen_check(s, a)) { \ 2233 uint32_t data = 0; \ 2234 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2235 gen_helper_##NAME##_h, \ 2236 gen_helper_##NAME##_w, \ 2237 }; \ 2238 TCGLabel *over = gen_new_label(); \ 2239 gen_set_rm(s, 7); \ 2240 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2241 \ 2242 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2243 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2244 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2245 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2246 vreg_ofs(s, a->rs2), cpu_env, \ 2247 s->vlen / 8, s->vlen / 8, data, \ 2248 fns[s->sew - 1]); \ 2249 gen_set_label(over); \ 2250 return true; \ 2251 } \ 2252 return false; \ 2253} 2254 2255GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) 2256GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) 2257GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) 2258GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) 2259GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) 2260 2261/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2262 2263/* 2264 * If the current SEW does not correspond to a supported IEEE floating-point 2265 * type, an illegal instruction exception is raised 2266 */ 2267static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2268{ 2269 return (vext_check_isa_ill(s) && 2270 vext_check_overlap_mask(s, a->rd, a->vm, false) && 2271 vext_check_reg(s, a->rd, false) && 2272 vext_check_reg(s, a->rs2, true) && 2273 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 2274 2 << s->lmul) && 2275 (s->lmul < 0x3) && (s->sew < 0x3) && (s->sew != 0)); 2276} 2277 2278#define GEN_OPFV_NARROW_TRANS(NAME) \ 2279static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2280{ \ 2281 if (opfv_narrow_check(s, a)) { \ 2282 uint32_t data = 0; \ 2283 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2284 gen_helper_##NAME##_h, \ 2285 gen_helper_##NAME##_w, \ 2286 }; \ 2287 TCGLabel *over = gen_new_label(); \ 2288 gen_set_rm(s, 7); \ 2289 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2290 \ 2291 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2292 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2293 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2294 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2295 vreg_ofs(s, a->rs2), cpu_env, \ 2296 s->vlen / 8, s->vlen / 8, data, \ 2297 fns[s->sew - 1]); \ 2298 gen_set_label(over); \ 2299 return true; \ 2300 } \ 2301 return false; \ 2302} 2303 2304GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) 2305GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) 2306GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) 2307GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) 2308GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) 2309 2310/* 2311 *** Vector Reduction Operations 2312 */ 2313/* Vector Single-Width Integer Reduction Instructions */ 2314static bool reduction_check(DisasContext *s, arg_rmrr *a) 2315{ 2316 return vext_check_isa_ill(s) && vext_check_reg(s, a->rs2, false); 2317} 2318 2319GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2320GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2321GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2322GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2323GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2324GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2325GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2326GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2327 2328/* Vector Widening Integer Reduction Instructions */ 2329GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_check) 2330GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_check) 2331 2332/* Vector Single-Width Floating-Point Reduction Instructions */ 2333GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) 2334GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) 2335GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) 2336 2337/* Vector Widening Floating-Point Reduction Instructions */ 2338GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) 2339 2340/* 2341 *** Vector Mask Operations 2342 */ 2343 2344/* Vector Mask-Register Logical Instructions */ 2345#define GEN_MM_TRANS(NAME) \ 2346static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2347{ \ 2348 if (vext_check_isa_ill(s)) { \ 2349 uint32_t data = 0; \ 2350 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2351 TCGLabel *over = gen_new_label(); \ 2352 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2353 \ 2354 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2355 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2356 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2357 vreg_ofs(s, a->rs1), \ 2358 vreg_ofs(s, a->rs2), cpu_env, \ 2359 s->vlen / 8, s->vlen / 8, data, fn); \ 2360 gen_set_label(over); \ 2361 return true; \ 2362 } \ 2363 return false; \ 2364} 2365 2366GEN_MM_TRANS(vmand_mm) 2367GEN_MM_TRANS(vmnand_mm) 2368GEN_MM_TRANS(vmandnot_mm) 2369GEN_MM_TRANS(vmxor_mm) 2370GEN_MM_TRANS(vmor_mm) 2371GEN_MM_TRANS(vmnor_mm) 2372GEN_MM_TRANS(vmornot_mm) 2373GEN_MM_TRANS(vmxnor_mm) 2374 2375/* Vector mask population count vmpopc */ 2376static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) 2377{ 2378 if (vext_check_isa_ill(s)) { 2379 TCGv_ptr src2, mask; 2380 TCGv dst; 2381 TCGv_i32 desc; 2382 uint32_t data = 0; 2383 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2384 data = FIELD_DP32(data, VDATA, VM, a->vm); 2385 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2386 2387 mask = tcg_temp_new_ptr(); 2388 src2 = tcg_temp_new_ptr(); 2389 dst = dest_gpr(s, a->rd); 2390 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2391 2392 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2393 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2394 2395 gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc); 2396 gen_set_gpr(s, a->rd, dst); 2397 2398 tcg_temp_free_ptr(mask); 2399 tcg_temp_free_ptr(src2); 2400 return true; 2401 } 2402 return false; 2403} 2404 2405/* vmfirst find-first-set mask bit */ 2406static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) 2407{ 2408 if (vext_check_isa_ill(s)) { 2409 TCGv_ptr src2, mask; 2410 TCGv dst; 2411 TCGv_i32 desc; 2412 uint32_t data = 0; 2413 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2414 data = FIELD_DP32(data, VDATA, VM, a->vm); 2415 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2416 2417 mask = tcg_temp_new_ptr(); 2418 src2 = tcg_temp_new_ptr(); 2419 dst = dest_gpr(s, a->rd); 2420 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2421 2422 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2423 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2424 2425 gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc); 2426 gen_set_gpr(s, a->rd, dst); 2427 2428 tcg_temp_free_ptr(mask); 2429 tcg_temp_free_ptr(src2); 2430 return true; 2431 } 2432 return false; 2433} 2434 2435/* vmsbf.m set-before-first mask bit */ 2436/* vmsif.m set-includ-first mask bit */ 2437/* vmsof.m set-only-first mask bit */ 2438#define GEN_M_TRANS(NAME) \ 2439static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2440{ \ 2441 if (vext_check_isa_ill(s)) { \ 2442 uint32_t data = 0; \ 2443 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2444 TCGLabel *over = gen_new_label(); \ 2445 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2446 \ 2447 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \ 2448 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2449 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2450 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2451 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2452 cpu_env, s->vlen / 8, s->vlen / 8, \ 2453 data, fn); \ 2454 gen_set_label(over); \ 2455 return true; \ 2456 } \ 2457 return false; \ 2458} 2459 2460GEN_M_TRANS(vmsbf_m) 2461GEN_M_TRANS(vmsif_m) 2462GEN_M_TRANS(vmsof_m) 2463 2464/* Vector Iota Instruction */ 2465static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2466{ 2467 if (vext_check_isa_ill(s) && 2468 vext_check_reg(s, a->rd, false) && 2469 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs2, 1) && 2470 (a->vm != 0 || a->rd != 0)) { 2471 uint32_t data = 0; 2472 TCGLabel *over = gen_new_label(); 2473 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2474 2475 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2476 data = FIELD_DP32(data, VDATA, VM, a->vm); 2477 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2478 static gen_helper_gvec_3_ptr * const fns[4] = { 2479 gen_helper_viota_m_b, gen_helper_viota_m_h, 2480 gen_helper_viota_m_w, gen_helper_viota_m_d, 2481 }; 2482 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2483 vreg_ofs(s, a->rs2), cpu_env, 2484 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 2485 gen_set_label(over); 2486 return true; 2487 } 2488 return false; 2489} 2490 2491/* Vector Element Index Instruction */ 2492static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 2493{ 2494 if (vext_check_isa_ill(s) && 2495 vext_check_reg(s, a->rd, false) && 2496 vext_check_overlap_mask(s, a->rd, a->vm, false)) { 2497 uint32_t data = 0; 2498 TCGLabel *over = gen_new_label(); 2499 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2500 2501 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2502 data = FIELD_DP32(data, VDATA, VM, a->vm); 2503 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2504 static gen_helper_gvec_2_ptr * const fns[4] = { 2505 gen_helper_vid_v_b, gen_helper_vid_v_h, 2506 gen_helper_vid_v_w, gen_helper_vid_v_d, 2507 }; 2508 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2509 cpu_env, s->vlen / 8, s->vlen / 8, 2510 data, fns[s->sew]); 2511 gen_set_label(over); 2512 return true; 2513 } 2514 return false; 2515} 2516 2517/* 2518 *** Vector Permutation Instructions 2519 */ 2520 2521/* Integer Extract Instruction */ 2522 2523static void load_element(TCGv_i64 dest, TCGv_ptr base, 2524 int ofs, int sew) 2525{ 2526 switch (sew) { 2527 case MO_8: 2528 tcg_gen_ld8u_i64(dest, base, ofs); 2529 break; 2530 case MO_16: 2531 tcg_gen_ld16u_i64(dest, base, ofs); 2532 break; 2533 case MO_32: 2534 tcg_gen_ld32u_i64(dest, base, ofs); 2535 break; 2536 case MO_64: 2537 tcg_gen_ld_i64(dest, base, ofs); 2538 break; 2539 default: 2540 g_assert_not_reached(); 2541 break; 2542 } 2543} 2544 2545/* offset of the idx element with base regsiter r */ 2546static uint32_t endian_ofs(DisasContext *s, int r, int idx) 2547{ 2548#ifdef HOST_WORDS_BIGENDIAN 2549 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 2550#else 2551 return vreg_ofs(s, r) + (idx << s->sew); 2552#endif 2553} 2554 2555/* adjust the index according to the endian */ 2556static void endian_adjust(TCGv_i32 ofs, int sew) 2557{ 2558#ifdef HOST_WORDS_BIGENDIAN 2559 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 2560#endif 2561} 2562 2563/* Load idx >= VLMAX ? 0 : vreg[idx] */ 2564static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 2565 int vreg, TCGv idx, int vlmax) 2566{ 2567 TCGv_i32 ofs = tcg_temp_new_i32(); 2568 TCGv_ptr base = tcg_temp_new_ptr(); 2569 TCGv_i64 t_idx = tcg_temp_new_i64(); 2570 TCGv_i64 t_vlmax, t_zero; 2571 2572 /* 2573 * Mask the index to the length so that we do 2574 * not produce an out-of-range load. 2575 */ 2576 tcg_gen_trunc_tl_i32(ofs, idx); 2577 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 2578 2579 /* Convert the index to an offset. */ 2580 endian_adjust(ofs, s->sew); 2581 tcg_gen_shli_i32(ofs, ofs, s->sew); 2582 2583 /* Convert the index to a pointer. */ 2584 tcg_gen_ext_i32_ptr(base, ofs); 2585 tcg_gen_add_ptr(base, base, cpu_env); 2586 2587 /* Perform the load. */ 2588 load_element(dest, base, 2589 vreg_ofs(s, vreg), s->sew); 2590 tcg_temp_free_ptr(base); 2591 tcg_temp_free_i32(ofs); 2592 2593 /* Flush out-of-range indexing to zero. */ 2594 t_vlmax = tcg_constant_i64(vlmax); 2595 t_zero = tcg_constant_i64(0); 2596 tcg_gen_extu_tl_i64(t_idx, idx); 2597 2598 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 2599 t_vlmax, dest, t_zero); 2600 2601 tcg_temp_free_i64(t_idx); 2602} 2603 2604static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 2605 int vreg, int idx) 2606{ 2607 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2608} 2609 2610static bool trans_vext_x_v(DisasContext *s, arg_r *a) 2611{ 2612 TCGv_i64 tmp = tcg_temp_new_i64(); 2613 TCGv dest = dest_gpr(s, a->rd); 2614 2615 if (a->rs1 == 0) { 2616 /* Special case vmv.x.s rd, vs2. */ 2617 vec_element_loadi(s, tmp, a->rs2, 0); 2618 } else { 2619 /* This instruction ignores LMUL and vector register groups */ 2620 int vlmax = s->vlen >> (3 + s->sew); 2621 vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); 2622 } 2623 2624 tcg_gen_trunc_i64_tl(dest, tmp); 2625 gen_set_gpr(s, a->rd, dest); 2626 2627 tcg_temp_free_i64(tmp); 2628 return true; 2629} 2630 2631/* Integer Scalar Move Instruction */ 2632 2633static void store_element(TCGv_i64 val, TCGv_ptr base, 2634 int ofs, int sew) 2635{ 2636 switch (sew) { 2637 case MO_8: 2638 tcg_gen_st8_i64(val, base, ofs); 2639 break; 2640 case MO_16: 2641 tcg_gen_st16_i64(val, base, ofs); 2642 break; 2643 case MO_32: 2644 tcg_gen_st32_i64(val, base, ofs); 2645 break; 2646 case MO_64: 2647 tcg_gen_st_i64(val, base, ofs); 2648 break; 2649 default: 2650 g_assert_not_reached(); 2651 break; 2652 } 2653} 2654 2655/* 2656 * Store vreg[idx] = val. 2657 * The index must be in range of VLMAX. 2658 */ 2659static void vec_element_storei(DisasContext *s, int vreg, 2660 int idx, TCGv_i64 val) 2661{ 2662 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2663} 2664 2665/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 2666static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 2667{ 2668 if (vext_check_isa_ill(s)) { 2669 /* This instruction ignores LMUL and vector register groups */ 2670 int maxsz = s->vlen >> 3; 2671 TCGv_i64 t1; 2672 TCGLabel *over = gen_new_label(); 2673 2674 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2675 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); 2676 if (a->rs1 == 0) { 2677 goto done; 2678 } 2679 2680 t1 = tcg_temp_new_i64(); 2681 tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); 2682 vec_element_storei(s, a->rd, 0, t1); 2683 tcg_temp_free_i64(t1); 2684 done: 2685 gen_set_label(over); 2686 return true; 2687 } 2688 return false; 2689} 2690 2691/* Floating-Point Scalar Move Instructions */ 2692static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 2693{ 2694 if (!s->vill && has_ext(s, RVF) && 2695 (s->mstatus_fs != 0) && (s->sew != 0)) { 2696 unsigned int len = 8 << s->sew; 2697 2698 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); 2699 if (len < 64) { 2700 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 2701 MAKE_64BIT_MASK(len, 64 - len)); 2702 } 2703 2704 mark_fs_dirty(s); 2705 return true; 2706 } 2707 return false; 2708} 2709 2710/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 2711static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 2712{ 2713 if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { 2714 TCGv_i64 t1; 2715 /* The instructions ignore LMUL and vector register group. */ 2716 uint32_t vlmax = s->vlen >> 3; 2717 2718 /* if vl == 0, skip vector register write back */ 2719 TCGLabel *over = gen_new_label(); 2720 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2721 2722 /* zeroed all elements */ 2723 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); 2724 2725 /* NaN-box f[rs1] as necessary for SEW */ 2726 t1 = tcg_temp_new_i64(); 2727 if (s->sew == MO_64 && !has_ext(s, RVD)) { 2728 tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); 2729 } else { 2730 tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); 2731 } 2732 vec_element_storei(s, a->rd, 0, t1); 2733 tcg_temp_free_i64(t1); 2734 gen_set_label(over); 2735 return true; 2736 } 2737 return false; 2738} 2739 2740/* Vector Slide Instructions */ 2741static bool slideup_check(DisasContext *s, arg_rmrr *a) 2742{ 2743 return (vext_check_isa_ill(s) && 2744 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2745 vext_check_reg(s, a->rd, false) && 2746 vext_check_reg(s, a->rs2, false) && 2747 (a->rd != a->rs2)); 2748} 2749 2750GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 2751GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 2752GEN_OPIVI_TRANS(vslideup_vi, 1, vslideup_vx, slideup_check) 2753 2754GEN_OPIVX_TRANS(vslidedown_vx, opivx_check) 2755GEN_OPIVX_TRANS(vslide1down_vx, opivx_check) 2756GEN_OPIVI_TRANS(vslidedown_vi, 1, vslidedown_vx, opivx_check) 2757 2758/* Vector Register Gather Instruction */ 2759static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 2760{ 2761 return (vext_check_isa_ill(s) && 2762 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2763 vext_check_reg(s, a->rd, false) && 2764 vext_check_reg(s, a->rs1, false) && 2765 vext_check_reg(s, a->rs2, false) && 2766 (a->rd != a->rs2) && (a->rd != a->rs1)); 2767} 2768 2769GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 2770 2771static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 2772{ 2773 return (vext_check_isa_ill(s) && 2774 vext_check_overlap_mask(s, a->rd, a->vm, true) && 2775 vext_check_reg(s, a->rd, false) && 2776 vext_check_reg(s, a->rs2, false) && 2777 (a->rd != a->rs2)); 2778} 2779 2780/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 2781static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 2782{ 2783 if (!vrgather_vx_check(s, a)) { 2784 return false; 2785 } 2786 2787 if (a->vm && s->vl_eq_vlmax) { 2788 int vlmax = s->vlen / s->mlen; 2789 TCGv_i64 dest = tcg_temp_new_i64(); 2790 2791 if (a->rs1 == 0) { 2792 vec_element_loadi(s, dest, a->rs2, 0); 2793 } else { 2794 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 2795 } 2796 2797 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2798 MAXSZ(s), MAXSZ(s), dest); 2799 tcg_temp_free_i64(dest); 2800 } else { 2801 static gen_helper_opivx * const fns[4] = { 2802 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2803 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2804 }; 2805 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 2806 } 2807 return true; 2808} 2809 2810/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 2811static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 2812{ 2813 if (!vrgather_vx_check(s, a)) { 2814 return false; 2815 } 2816 2817 if (a->vm && s->vl_eq_vlmax) { 2818 if (a->rs1 >= s->vlen / s->mlen) { 2819 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), 2820 MAXSZ(s), MAXSZ(s), 0); 2821 } else { 2822 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 2823 endian_ofs(s, a->rs2, a->rs1), 2824 MAXSZ(s), MAXSZ(s)); 2825 } 2826 } else { 2827 static gen_helper_opivx * const fns[4] = { 2828 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 2829 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 2830 }; 2831 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s, 1); 2832 } 2833 return true; 2834} 2835 2836/* Vector Compress Instruction */ 2837static bool vcompress_vm_check(DisasContext *s, arg_r *a) 2838{ 2839 return (vext_check_isa_ill(s) && 2840 vext_check_reg(s, a->rd, false) && 2841 vext_check_reg(s, a->rs2, false) && 2842 vext_check_overlap_group(a->rd, 1 << s->lmul, a->rs1, 1) && 2843 (a->rd != a->rs2)); 2844} 2845 2846static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 2847{ 2848 if (vcompress_vm_check(s, a)) { 2849 uint32_t data = 0; 2850 static gen_helper_gvec_4_ptr * const fns[4] = { 2851 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 2852 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 2853 }; 2854 TCGLabel *over = gen_new_label(); 2855 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2856 2857 data = FIELD_DP32(data, VDATA, MLEN, s->mlen); 2858 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2859 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2860 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 2861 cpu_env, s->vlen / 8, s->vlen / 8, data, 2862 fns[s->sew]); 2863 gen_set_label(over); 2864 return true; 2865 } 2866 return false; 2867} 2868