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