1/* 2 * 3 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2 or later, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17#include "tcg/tcg-op-gvec.h" 18#include "tcg/tcg-gvec-desc.h" 19#include "internals.h" 20 21static inline bool is_overlapped(const int8_t astart, int8_t asize, 22 const int8_t bstart, int8_t bsize) 23{ 24 const int8_t aend = astart + asize; 25 const int8_t bend = bstart + bsize; 26 27 return MAX(aend, bend) - MIN(astart, bstart) < asize + bsize; 28} 29 30static bool require_rvv(DisasContext *s) 31{ 32 return s->mstatus_vs != EXT_STATUS_DISABLED; 33} 34 35static bool require_rvf(DisasContext *s) 36{ 37 if (s->mstatus_fs == EXT_STATUS_DISABLED) { 38 return false; 39 } 40 41 switch (s->sew) { 42 case MO_16: 43 return s->cfg_ptr->ext_zvfh; 44 case MO_32: 45 return s->cfg_ptr->ext_zve32f; 46 case MO_64: 47 return s->cfg_ptr->ext_zve64d; 48 default: 49 return false; 50 } 51} 52 53static bool require_rvfmin(DisasContext *s) 54{ 55 if (s->mstatus_fs == EXT_STATUS_DISABLED) { 56 return false; 57 } 58 59 switch (s->sew) { 60 case MO_16: 61 return s->cfg_ptr->ext_zvfhmin; 62 case MO_32: 63 return s->cfg_ptr->ext_zve32f; 64 default: 65 return false; 66 } 67} 68 69static bool require_scale_rvf(DisasContext *s) 70{ 71 if (s->mstatus_fs == EXT_STATUS_DISABLED) { 72 return false; 73 } 74 75 switch (s->sew) { 76 case MO_8: 77 return s->cfg_ptr->ext_zvfh; 78 case MO_16: 79 return s->cfg_ptr->ext_zve32f; 80 case MO_32: 81 return s->cfg_ptr->ext_zve64d; 82 default: 83 return false; 84 } 85} 86 87static bool require_scale_rvfmin(DisasContext *s) 88{ 89 if (s->mstatus_fs == EXT_STATUS_DISABLED) { 90 return false; 91 } 92 93 switch (s->sew) { 94 case MO_16: 95 return s->cfg_ptr->ext_zve32f; 96 case MO_32: 97 return s->cfg_ptr->ext_zve64d; 98 default: 99 return false; 100 } 101} 102 103/* Destination vector register group cannot overlap source mask register. */ 104static bool require_vm(int vm, int vd) 105{ 106 return (vm != 0 || vd != 0); 107} 108 109static bool require_nf(int vd, int nf, int lmul) 110{ 111 int size = nf << MAX(lmul, 0); 112 return size <= 8 && vd + size <= 32; 113} 114 115/* 116 * Vector register should aligned with the passed-in LMUL (EMUL). 117 * If LMUL < 0, i.e. fractional LMUL, any vector register is allowed. 118 */ 119static bool require_align(const int8_t val, const int8_t lmul) 120{ 121 return lmul <= 0 || extract32(val, 0, lmul) == 0; 122} 123 124/* 125 * A destination vector register group can overlap a source vector 126 * register group only if one of the following holds: 127 * 1. The destination EEW equals the source EEW. 128 * 2. The destination EEW is smaller than the source EEW and the overlap 129 * is in the lowest-numbered part of the source register group. 130 * 3. The destination EEW is greater than the source EEW, the source EMUL 131 * is at least 1, and the overlap is in the highest-numbered part of 132 * the destination register group. 133 * (Section 5.2) 134 * 135 * This function returns true if one of the following holds: 136 * * Destination vector register group does not overlap a source vector 137 * register group. 138 * * Rule 3 met. 139 * For rule 1, overlap is allowed so this function doesn't need to be called. 140 * For rule 2, (vd == vs). Caller has to check whether: (vd != vs) before 141 * calling this function. 142 */ 143static bool require_noover(const int8_t dst, const int8_t dst_lmul, 144 const int8_t src, const int8_t src_lmul) 145{ 146 int8_t dst_size = dst_lmul <= 0 ? 1 : 1 << dst_lmul; 147 int8_t src_size = src_lmul <= 0 ? 1 : 1 << src_lmul; 148 149 /* Destination EEW is greater than the source EEW, check rule 3. */ 150 if (dst_size > src_size) { 151 if (dst < src && 152 src_lmul >= 0 && 153 is_overlapped(dst, dst_size, src, src_size) && 154 !is_overlapped(dst, dst_size, src + src_size, src_size)) { 155 return true; 156 } 157 } 158 159 return !is_overlapped(dst, dst_size, src, src_size); 160} 161 162static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) 163{ 164 TCGv s1, dst; 165 166 if (!require_rvv(s) || !s->cfg_ptr->ext_zve32x) { 167 return false; 168 } 169 170 dst = dest_gpr(s, rd); 171 172 if (rd == 0 && rs1 == 0) { 173 s1 = tcg_temp_new(); 174 tcg_gen_mov_tl(s1, cpu_vl); 175 } else if (rs1 == 0) { 176 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ 177 s1 = tcg_constant_tl(RV_VLEN_MAX); 178 } else { 179 s1 = get_gpr(s, rs1, EXT_ZERO); 180 } 181 182 gen_helper_vsetvl(dst, tcg_env, s1, s2); 183 gen_set_gpr(s, rd, dst); 184 finalize_rvv_inst(s); 185 186 gen_update_pc(s, s->cur_insn_len); 187 lookup_and_goto_ptr(s); 188 s->base.is_jmp = DISAS_NORETURN; 189 return true; 190} 191 192static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) 193{ 194 TCGv dst; 195 196 if (!require_rvv(s) || !s->cfg_ptr->ext_zve32x) { 197 return false; 198 } 199 200 dst = dest_gpr(s, rd); 201 202 gen_helper_vsetvl(dst, tcg_env, s1, s2); 203 gen_set_gpr(s, rd, dst); 204 finalize_rvv_inst(s); 205 gen_update_pc(s, s->cur_insn_len); 206 lookup_and_goto_ptr(s); 207 s->base.is_jmp = DISAS_NORETURN; 208 209 return true; 210} 211 212static bool trans_vsetvl(DisasContext *s, arg_vsetvl *a) 213{ 214 TCGv s2 = get_gpr(s, a->rs2, EXT_ZERO); 215 return do_vsetvl(s, a->rd, a->rs1, s2); 216} 217 218static bool trans_vsetvli(DisasContext *s, arg_vsetvli *a) 219{ 220 TCGv s2 = tcg_constant_tl(a->zimm); 221 return do_vsetvl(s, a->rd, a->rs1, s2); 222} 223 224static bool trans_vsetivli(DisasContext *s, arg_vsetivli *a) 225{ 226 TCGv s1 = tcg_constant_tl(a->rs1); 227 TCGv s2 = tcg_constant_tl(a->zimm); 228 return do_vsetivli(s, a->rd, s1, s2); 229} 230 231/* vector register offset from env */ 232static uint32_t vreg_ofs(DisasContext *s, int reg) 233{ 234 return offsetof(CPURISCVState, vreg) + reg * s->cfg_ptr->vlenb; 235} 236 237/* check functions */ 238 239/* 240 * Vector unit-stride, strided, unit-stride segment, strided segment 241 * store check function. 242 * 243 * Rules to be checked here: 244 * 1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3) 245 * 2. Destination vector register number is multiples of EMUL. 246 * (Section 3.4.2, 7.3) 247 * 3. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8) 248 * 4. Vector register numbers accessed by the segment load or store 249 * cannot increment past 31. (Section 7.8) 250 */ 251static bool vext_check_store(DisasContext *s, int vd, int nf, uint8_t eew) 252{ 253 int8_t emul = eew - s->sew + s->lmul; 254 return (emul >= -3 && emul <= 3) && 255 require_align(vd, emul) && 256 require_nf(vd, nf, emul); 257} 258 259/* 260 * Vector unit-stride, strided, unit-stride segment, strided segment 261 * load check function. 262 * 263 * Rules to be checked here: 264 * 1. All rules applies to store instructions are applies 265 * to load instructions. 266 * 2. Destination vector register group for a masked vector 267 * instruction cannot overlap the source mask register (v0). 268 * (Section 5.3) 269 */ 270static bool vext_check_load(DisasContext *s, int vd, int nf, int vm, 271 uint8_t eew) 272{ 273 return vext_check_store(s, vd, nf, eew) && require_vm(vm, vd); 274} 275 276/* 277 * Vector indexed, indexed segment store check function. 278 * 279 * Rules to be checked here: 280 * 1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3) 281 * 2. Index vector register number is multiples of EMUL. 282 * (Section 3.4.2, 7.3) 283 * 3. Destination vector register number is multiples of LMUL. 284 * (Section 3.4.2, 7.3) 285 * 4. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8) 286 * 5. Vector register numbers accessed by the segment load or store 287 * cannot increment past 31. (Section 7.8) 288 */ 289static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf, 290 uint8_t eew) 291{ 292 int8_t emul = eew - s->sew + s->lmul; 293 bool ret = (emul >= -3 && emul <= 3) && 294 require_align(vs2, emul) && 295 require_align(vd, s->lmul) && 296 require_nf(vd, nf, s->lmul); 297 298 /* 299 * V extension supports all vector load and store instructions, 300 * except V extension does not support EEW=64 for index values 301 * when XLEN=32. (Section 18.3) 302 */ 303 if (get_xl(s) == MXL_RV32) { 304 ret &= (eew != MO_64); 305 } 306 307 return ret; 308} 309 310/* 311 * Vector indexed, indexed segment load check function. 312 * 313 * Rules to be checked here: 314 * 1. All rules applies to store instructions are applies 315 * to load instructions. 316 * 2. Destination vector register group for a masked vector 317 * instruction cannot overlap the source mask register (v0). 318 * (Section 5.3) 319 * 3. Destination vector register cannot overlap a source vector 320 * register (vs2) group. 321 * (Section 5.2) 322 * 4. Destination vector register groups cannot overlap 323 * the source vector register (vs2) group for 324 * indexed segment load instructions. (Section 7.8.3) 325 */ 326static bool vext_check_ld_index(DisasContext *s, int vd, int vs2, 327 int nf, int vm, uint8_t eew) 328{ 329 int8_t seg_vd; 330 int8_t emul = eew - s->sew + s->lmul; 331 bool ret = vext_check_st_index(s, vd, vs2, nf, eew) && 332 require_vm(vm, vd); 333 334 /* Each segment register group has to follow overlap rules. */ 335 for (int i = 0; i < nf; ++i) { 336 seg_vd = vd + (1 << MAX(s->lmul, 0)) * i; 337 338 if (eew > s->sew) { 339 if (seg_vd != vs2) { 340 ret &= require_noover(seg_vd, s->lmul, vs2, emul); 341 } 342 } else if (eew < s->sew) { 343 ret &= require_noover(seg_vd, s->lmul, vs2, emul); 344 } 345 346 /* 347 * Destination vector register groups cannot overlap 348 * the source vector register (vs2) group for 349 * indexed segment load instructions. 350 */ 351 if (nf > 1) { 352 ret &= !is_overlapped(seg_vd, 1 << MAX(s->lmul, 0), 353 vs2, 1 << MAX(emul, 0)); 354 } 355 } 356 return ret; 357} 358 359static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) 360{ 361 return require_vm(vm, vd) && 362 require_align(vd, s->lmul) && 363 require_align(vs, s->lmul); 364} 365 366/* 367 * Check function for vector instruction with format: 368 * single-width result and single-width sources (SEW = SEW op SEW) 369 * 370 * Rules to be checked here: 371 * 1. Destination vector register group for a masked vector 372 * instruction cannot overlap the source mask register (v0). 373 * (Section 5.3) 374 * 2. Destination vector register number is multiples of LMUL. 375 * (Section 3.4.2) 376 * 3. Source (vs2, vs1) vector register number are multiples of LMUL. 377 * (Section 3.4.2) 378 */ 379static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm) 380{ 381 return vext_check_ss(s, vd, vs2, vm) && 382 require_align(vs1, s->lmul); 383} 384 385static bool vext_check_ms(DisasContext *s, int vd, int vs) 386{ 387 bool ret = require_align(vs, s->lmul); 388 if (vd != vs) { 389 ret &= require_noover(vd, 0, vs, s->lmul); 390 } 391 return ret; 392} 393 394/* 395 * Check function for maskable vector instruction with format: 396 * single-width result and single-width sources (SEW = SEW op SEW) 397 * 398 * Rules to be checked here: 399 * 1. Source (vs2, vs1) vector register number are multiples of LMUL. 400 * (Section 3.4.2) 401 * 2. Destination vector register cannot overlap a source vector 402 * register (vs2, vs1) group. 403 * (Section 5.2) 404 * 3. The destination vector register group for a masked vector 405 * instruction cannot overlap the source mask register (v0), 406 * unless the destination vector register is being written 407 * with a mask value (e.g., comparisons) or the scalar result 408 * of a reduction. (Section 5.3) 409 */ 410static bool vext_check_mss(DisasContext *s, int vd, int vs1, int vs2) 411{ 412 bool ret = vext_check_ms(s, vd, vs2) && 413 require_align(vs1, s->lmul); 414 if (vd != vs1) { 415 ret &= require_noover(vd, 0, vs1, s->lmul); 416 } 417 return ret; 418} 419 420/* 421 * Common check function for vector widening instructions 422 * of double-width result (2*SEW). 423 * 424 * Rules to be checked here: 425 * 1. The largest vector register group used by an instruction 426 * can not be greater than 8 vector registers (Section 5.2): 427 * => LMUL < 8. 428 * => SEW < 64. 429 * 2. Double-width SEW cannot greater than ELEN. 430 * 3. Destination vector register number is multiples of 2 * LMUL. 431 * (Section 3.4.2) 432 * 4. Destination vector register group for a masked vector 433 * instruction cannot overlap the source mask register (v0). 434 * (Section 5.3) 435 */ 436static bool vext_wide_check_common(DisasContext *s, int vd, int vm) 437{ 438 return (s->lmul <= 2) && 439 (s->sew < MO_64) && 440 ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)) && 441 require_align(vd, s->lmul + 1) && 442 require_vm(vm, vd); 443} 444 445/* 446 * Common check function for vector narrowing instructions 447 * of single-width result (SEW) and double-width source (2*SEW). 448 * 449 * Rules to be checked here: 450 * 1. The largest vector register group used by an instruction 451 * can not be greater than 8 vector registers (Section 5.2): 452 * => LMUL < 8. 453 * => SEW < 64. 454 * 2. Double-width SEW cannot greater than ELEN. 455 * 3. Source vector register number is multiples of 2 * LMUL. 456 * (Section 3.4.2) 457 * 4. Destination vector register number is multiples of LMUL. 458 * (Section 3.4.2) 459 * 5. Destination vector register group for a masked vector 460 * instruction cannot overlap the source mask register (v0). 461 * (Section 5.3) 462 */ 463static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2, 464 int vm) 465{ 466 return (s->lmul <= 2) && 467 (s->sew < MO_64) && 468 ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)) && 469 require_align(vs2, s->lmul + 1) && 470 require_align(vd, s->lmul) && 471 require_vm(vm, vd); 472} 473 474static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) 475{ 476 return vext_wide_check_common(s, vd, vm) && 477 require_align(vs, s->lmul) && 478 require_noover(vd, s->lmul + 1, vs, s->lmul); 479} 480 481static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) 482{ 483 return vext_wide_check_common(s, vd, vm) && 484 require_align(vs, s->lmul + 1); 485} 486 487/* 488 * Check function for vector instruction with format: 489 * double-width result and single-width sources (2*SEW = SEW op SEW) 490 * 491 * Rules to be checked here: 492 * 1. All rules in defined in widen common rules are applied. 493 * 2. Source (vs2, vs1) vector register number are multiples of LMUL. 494 * (Section 3.4.2) 495 * 3. Destination vector register cannot overlap a source vector 496 * register (vs2, vs1) group. 497 * (Section 5.2) 498 */ 499static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) 500{ 501 return vext_check_ds(s, vd, vs2, vm) && 502 require_align(vs1, s->lmul) && 503 require_noover(vd, s->lmul + 1, vs1, s->lmul); 504} 505 506/* 507 * Check function for vector instruction with format: 508 * double-width result and double-width source1 and single-width 509 * source2 (2*SEW = 2*SEW op SEW) 510 * 511 * Rules to be checked here: 512 * 1. All rules in defined in widen common rules are applied. 513 * 2. Source 1 (vs2) vector register number is multiples of 2 * LMUL. 514 * (Section 3.4.2) 515 * 3. Source 2 (vs1) vector register number is multiples of LMUL. 516 * (Section 3.4.2) 517 * 4. Destination vector register cannot overlap a source vector 518 * register (vs1) group. 519 * (Section 5.2) 520 */ 521static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm) 522{ 523 return vext_check_ds(s, vd, vs1, vm) && 524 require_align(vs2, s->lmul + 1); 525} 526 527static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) 528{ 529 bool ret = vext_narrow_check_common(s, vd, vs, vm); 530 if (vd != vs) { 531 ret &= require_noover(vd, s->lmul, vs, s->lmul + 1); 532 } 533 return ret; 534} 535 536/* 537 * Check function for vector instruction with format: 538 * single-width result and double-width source 1 and single-width 539 * source 2 (SEW = 2*SEW op SEW) 540 * 541 * Rules to be checked here: 542 * 1. All rules in defined in narrow common rules are applied. 543 * 2. Destination vector register cannot overlap a source vector 544 * register (vs2) group. 545 * (Section 5.2) 546 * 3. Source 2 (vs1) vector register number is multiples of LMUL. 547 * (Section 3.4.2) 548 */ 549static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm) 550{ 551 return vext_check_sd(s, vd, vs2, vm) && 552 require_align(vs1, s->lmul); 553} 554 555/* 556 * Check function for vector reduction instructions. 557 * 558 * Rules to be checked here: 559 * 1. Source 1 (vs2) vector register number is multiples of LMUL. 560 * (Section 3.4.2) 561 */ 562static bool vext_check_reduction(DisasContext *s, int vs2) 563{ 564 return require_align(vs2, s->lmul) && s->vstart_eq_zero; 565} 566 567/* 568 * Check function for vector slide instructions. 569 * 570 * Rules to be checked here: 571 * 1. Source 1 (vs2) vector register number is multiples of LMUL. 572 * (Section 3.4.2) 573 * 2. Destination vector register number is multiples of LMUL. 574 * (Section 3.4.2) 575 * 3. Destination vector register group for a masked vector 576 * instruction cannot overlap the source mask register (v0). 577 * (Section 5.3) 578 * 4. The destination vector register group for vslideup, vslide1up, 579 * vfslide1up, cannot overlap the source vector register (vs2) group. 580 * (Section 5.2, 16.3.1, 16.3.3) 581 */ 582static bool vext_check_slide(DisasContext *s, int vd, int vs2, 583 int vm, bool is_over) 584{ 585 bool ret = require_align(vs2, s->lmul) && 586 require_align(vd, s->lmul) && 587 require_vm(vm, vd); 588 if (is_over) { 589 ret &= (vd != vs2); 590 } 591 return ret; 592} 593 594/* 595 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present. 596 * So RVV is also be checked in this function. 597 */ 598static bool vext_check_isa_ill(DisasContext *s) 599{ 600 return !s->vill; 601} 602 603/* common translation macro */ 604#define GEN_VEXT_TRANS(NAME, EEW, ARGTYPE, OP, CHECK) \ 605static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE * a) \ 606{ \ 607 if (CHECK(s, a, EEW)) { \ 608 return OP(s, a, EEW); \ 609 } \ 610 return false; \ 611} 612 613static uint8_t vext_get_emul(DisasContext *s, uint8_t eew) 614{ 615 int8_t emul = eew - s->sew + s->lmul; 616 return emul < 0 ? 0 : emul; 617} 618 619/* 620 *** unit stride load and store 621 */ 622typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv, 623 TCGv_env, TCGv_i32); 624 625static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, 626 gen_helper_ldst_us *fn, DisasContext *s, 627 bool is_store) 628{ 629 TCGv_ptr dest, mask; 630 TCGv base; 631 TCGv_i32 desc; 632 633 dest = tcg_temp_new_ptr(); 634 mask = tcg_temp_new_ptr(); 635 base = get_gpr(s, rs1, EXT_NONE); 636 637 /* 638 * As simd_desc supports at most 2048 bytes, and in this implementation, 639 * the max vector group length is 4096 bytes. So split it into two parts. 640 * 641 * The first part is vlen in bytes (vlenb), encoded in maxsz of simd_desc. 642 * The second part is lmul, encoded in data of simd_desc. 643 */ 644 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 645 s->cfg_ptr->vlenb, data)); 646 647 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 648 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 649 650 /* 651 * According to the specification 652 * 653 * Additionally, if the Ztso extension is implemented, then vector memory 654 * instructions in the V extension and Zve family of extensions follow 655 * RVTSO at the instruction level. The Ztso extension does not 656 * strengthen the ordering of intra-instruction element accesses. 657 * 658 * as a result neither ordered nor unordered accesses from the V 659 * instructions need ordering within the loop but we do still need barriers 660 * around the loop. 661 */ 662 if (is_store && s->ztso) { 663 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); 664 } 665 666 mark_vs_dirty(s); 667 668 fn(dest, mask, base, tcg_env, desc); 669 670 if (!is_store && s->ztso) { 671 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); 672 } 673 674 finalize_rvv_inst(s); 675 return true; 676} 677 678static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 679{ 680 uint32_t data = 0; 681 gen_helper_ldst_us *fn; 682 static gen_helper_ldst_us * const fns[2][4] = { 683 /* masked unit stride load */ 684 { gen_helper_vle8_v_mask, gen_helper_vle16_v_mask, 685 gen_helper_vle32_v_mask, gen_helper_vle64_v_mask }, 686 /* unmasked unit stride load */ 687 { gen_helper_vle8_v, gen_helper_vle16_v, 688 gen_helper_vle32_v, gen_helper_vle64_v } 689 }; 690 691 fn = fns[a->vm][eew]; 692 if (fn == NULL) { 693 return false; 694 } 695 696 /* 697 * Vector load/store instructions have the EEW encoded 698 * directly in the instructions. The maximum vector size is 699 * calculated with EMUL rather than LMUL. 700 */ 701 uint8_t emul = vext_get_emul(s, eew); 702 data = FIELD_DP32(data, VDATA, VM, a->vm); 703 data = FIELD_DP32(data, VDATA, LMUL, emul); 704 data = FIELD_DP32(data, VDATA, NF, a->nf); 705 data = FIELD_DP32(data, VDATA, VTA, s->vta); 706 data = FIELD_DP32(data, VDATA, VMA, s->vma); 707 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 708} 709 710static bool ld_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 711{ 712 return require_rvv(s) && 713 vext_check_isa_ill(s) && 714 vext_check_load(s, a->rd, a->nf, a->vm, eew); 715} 716 717GEN_VEXT_TRANS(vle8_v, MO_8, r2nfvm, ld_us_op, ld_us_check) 718GEN_VEXT_TRANS(vle16_v, MO_16, r2nfvm, ld_us_op, ld_us_check) 719GEN_VEXT_TRANS(vle32_v, MO_32, r2nfvm, ld_us_op, ld_us_check) 720GEN_VEXT_TRANS(vle64_v, MO_64, r2nfvm, ld_us_op, ld_us_check) 721 722static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 723{ 724 uint32_t data = 0; 725 gen_helper_ldst_us *fn; 726 static gen_helper_ldst_us * const fns[2][4] = { 727 /* masked unit stride store */ 728 { gen_helper_vse8_v_mask, gen_helper_vse16_v_mask, 729 gen_helper_vse32_v_mask, gen_helper_vse64_v_mask }, 730 /* unmasked unit stride store */ 731 { gen_helper_vse8_v, gen_helper_vse16_v, 732 gen_helper_vse32_v, gen_helper_vse64_v } 733 }; 734 735 fn = fns[a->vm][eew]; 736 if (fn == NULL) { 737 return false; 738 } 739 740 uint8_t emul = vext_get_emul(s, eew); 741 data = FIELD_DP32(data, VDATA, VM, a->vm); 742 data = FIELD_DP32(data, VDATA, LMUL, emul); 743 data = FIELD_DP32(data, VDATA, NF, a->nf); 744 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 745} 746 747static bool st_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 748{ 749 return require_rvv(s) && 750 vext_check_isa_ill(s) && 751 vext_check_store(s, a->rd, a->nf, eew); 752} 753 754GEN_VEXT_TRANS(vse8_v, MO_8, r2nfvm, st_us_op, st_us_check) 755GEN_VEXT_TRANS(vse16_v, MO_16, r2nfvm, st_us_op, st_us_check) 756GEN_VEXT_TRANS(vse32_v, MO_32, r2nfvm, st_us_op, st_us_check) 757GEN_VEXT_TRANS(vse64_v, MO_64, r2nfvm, st_us_op, st_us_check) 758 759/* 760 *** unit stride mask load and store 761 */ 762static bool ld_us_mask_op(DisasContext *s, arg_vlm_v *a, uint8_t eew) 763{ 764 uint32_t data = 0; 765 gen_helper_ldst_us *fn = gen_helper_vlm_v; 766 767 /* EMUL = 1, NFIELDS = 1 */ 768 data = FIELD_DP32(data, VDATA, LMUL, 0); 769 data = FIELD_DP32(data, VDATA, NF, 1); 770 /* Mask destination register are always tail-agnostic */ 771 data = FIELD_DP32(data, VDATA, VTA, s->cfg_vta_all_1s); 772 data = FIELD_DP32(data, VDATA, VMA, s->vma); 773 data = FIELD_DP32(data, VDATA, VM, 1); 774 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 775} 776 777static bool ld_us_mask_check(DisasContext *s, arg_vlm_v *a, uint8_t eew) 778{ 779 /* EMUL = 1, NFIELDS = 1 */ 780 return require_rvv(s) && vext_check_isa_ill(s); 781} 782 783static bool st_us_mask_op(DisasContext *s, arg_vsm_v *a, uint8_t eew) 784{ 785 uint32_t data = 0; 786 gen_helper_ldst_us *fn = gen_helper_vsm_v; 787 788 /* EMUL = 1, NFIELDS = 1 */ 789 data = FIELD_DP32(data, VDATA, LMUL, 0); 790 data = FIELD_DP32(data, VDATA, NF, 1); 791 data = FIELD_DP32(data, VDATA, VM, 1); 792 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 793} 794 795static bool st_us_mask_check(DisasContext *s, arg_vsm_v *a, uint8_t eew) 796{ 797 /* EMUL = 1, NFIELDS = 1 */ 798 return require_rvv(s) && vext_check_isa_ill(s); 799} 800 801GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld_us_mask_check) 802GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check) 803 804/* 805 * MAXSZ returns the maximum vector size can be operated in bytes, 806 * which is used in GVEC IR when vl_eq_vlmax flag is set to true 807 * to accelerate vector operation. 808 */ 809static inline uint32_t MAXSZ(DisasContext *s) 810{ 811 int max_sz = s->cfg_ptr->vlenb << 3; 812 return max_sz >> (3 - s->lmul); 813} 814 815static inline uint32_t get_log2(uint32_t a) 816{ 817 uint32_t i = 0; 818 for (; a > 0;) { 819 a >>= 1; 820 i++; 821 } 822 return i; 823} 824 825typedef void gen_tl_ldst(TCGv, TCGv_ptr, tcg_target_long); 826 827/* 828 * Simulate the strided load/store main loop: 829 * 830 * for (i = env->vstart; i < env->vl; env->vstart = ++i) { 831 * k = 0; 832 * while (k < nf) { 833 * if (!vm && !vext_elem_mask(v0, i)) { 834 * vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, 835 * (i + k * max_elems + 1) * esz); 836 * k++; 837 * continue; 838 * } 839 * target_ulong addr = base + stride * i + (k << log2_esz); 840 * ldst(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); 841 * k++; 842 * } 843 * } 844 */ 845static void gen_ldst_stride_main_loop(DisasContext *s, TCGv dest, uint32_t rs1, 846 uint32_t rs2, uint32_t vm, uint32_t nf, 847 gen_tl_ldst *ld_fn, gen_tl_ldst *st_fn, 848 bool is_load) 849{ 850 TCGv addr = tcg_temp_new(); 851 TCGv base = get_gpr(s, rs1, EXT_NONE); 852 TCGv stride = get_gpr(s, rs2, EXT_NONE); 853 854 TCGv i = tcg_temp_new(); 855 TCGv i_esz = tcg_temp_new(); 856 TCGv k = tcg_temp_new(); 857 TCGv k_esz = tcg_temp_new(); 858 TCGv k_max = tcg_temp_new(); 859 TCGv mask = tcg_temp_new(); 860 TCGv mask_offs = tcg_temp_new(); 861 TCGv mask_offs_64 = tcg_temp_new(); 862 TCGv mask_elem = tcg_temp_new(); 863 TCGv mask_offs_rem = tcg_temp_new(); 864 TCGv vreg = tcg_temp_new(); 865 TCGv dest_offs = tcg_temp_new(); 866 TCGv stride_offs = tcg_temp_new(); 867 868 uint32_t max_elems = MAXSZ(s) >> s->sew; 869 870 TCGLabel *start = gen_new_label(); 871 TCGLabel *end = gen_new_label(); 872 TCGLabel *start_k = gen_new_label(); 873 TCGLabel *inc_k = gen_new_label(); 874 TCGLabel *end_k = gen_new_label(); 875 876 MemOp atomicity = MO_ATOM_NONE; 877 if (s->sew == 0) { 878 atomicity = MO_ATOM_NONE; 879 } else { 880 atomicity = MO_ATOM_IFALIGN_PAIR; 881 } 882 883 mark_vs_dirty(s); 884 885 tcg_gen_addi_tl(mask, (TCGv)tcg_env, vreg_ofs(s, 0)); 886 887 /* Start of outer loop. */ 888 tcg_gen_mov_tl(i, cpu_vstart); 889 gen_set_label(start); 890 tcg_gen_brcond_tl(TCG_COND_GE, i, cpu_vl, end); 891 tcg_gen_shli_tl(i_esz, i, s->sew); 892 /* Start of inner loop. */ 893 tcg_gen_movi_tl(k, 0); 894 gen_set_label(start_k); 895 tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end_k); 896 /* 897 * If we are in mask agnostic regime and the operation is not unmasked we 898 * set the inactive elements to 1. 899 */ 900 if (!vm && s->vma) { 901 TCGLabel *active_element = gen_new_label(); 902 /* (i + k * max_elems) * esz */ 903 tcg_gen_shli_tl(mask_offs, k, get_log2(max_elems << s->sew)); 904 tcg_gen_add_tl(mask_offs, mask_offs, i_esz); 905 906 /* 907 * Check whether the i bit of the mask is 0 or 1. 908 * 909 * static inline int vext_elem_mask(void *v0, int index) 910 * { 911 * int idx = index / 64; 912 * int pos = index % 64; 913 * return (((uint64_t *)v0)[idx] >> pos) & 1; 914 * } 915 */ 916 tcg_gen_shri_tl(mask_offs_64, mask_offs, 3); 917 tcg_gen_add_tl(mask_offs_64, mask_offs_64, mask); 918 tcg_gen_ld_i64((TCGv_i64)mask_elem, (TCGv_ptr)mask_offs_64, 0); 919 tcg_gen_rem_tl(mask_offs_rem, mask_offs, tcg_constant_tl(8)); 920 tcg_gen_shr_tl(mask_elem, mask_elem, mask_offs_rem); 921 tcg_gen_andi_tl(mask_elem, mask_elem, 1); 922 tcg_gen_brcond_tl(TCG_COND_NE, mask_elem, tcg_constant_tl(0), 923 active_element); 924 /* 925 * Set masked-off elements in the destination vector register to 1s. 926 * Store instructions simply skip this bit as memory ops access memory 927 * only for active elements. 928 */ 929 if (is_load) { 930 tcg_gen_shli_tl(mask_offs, mask_offs, s->sew); 931 tcg_gen_add_tl(mask_offs, mask_offs, dest); 932 st_fn(tcg_constant_tl(-1), (TCGv_ptr)mask_offs, 0); 933 } 934 tcg_gen_br(inc_k); 935 gen_set_label(active_element); 936 } 937 /* 938 * The element is active, calculate the address with stride: 939 * target_ulong addr = base + stride * i + (k << log2_esz); 940 */ 941 tcg_gen_mul_tl(stride_offs, stride, i); 942 tcg_gen_shli_tl(k_esz, k, s->sew); 943 tcg_gen_add_tl(stride_offs, stride_offs, k_esz); 944 tcg_gen_add_tl(addr, base, stride_offs); 945 /* Calculate the offset in the dst/src vector register. */ 946 tcg_gen_shli_tl(k_max, k, get_log2(max_elems)); 947 tcg_gen_add_tl(dest_offs, i, k_max); 948 tcg_gen_shli_tl(dest_offs, dest_offs, s->sew); 949 tcg_gen_add_tl(dest_offs, dest_offs, dest); 950 if (is_load) { 951 tcg_gen_qemu_ld_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); 952 st_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); 953 } else { 954 ld_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); 955 tcg_gen_qemu_st_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); 956 } 957 /* 958 * We don't execute the load/store above if the element was inactive. 959 * We jump instead directly to incrementing k and continuing the loop. 960 */ 961 if (!vm && s->vma) { 962 gen_set_label(inc_k); 963 } 964 tcg_gen_addi_tl(k, k, 1); 965 tcg_gen_br(start_k); 966 /* End of the inner loop. */ 967 gen_set_label(end_k); 968 969 tcg_gen_addi_tl(i, i, 1); 970 tcg_gen_mov_tl(cpu_vstart, i); 971 tcg_gen_br(start); 972 973 /* End of the outer loop. */ 974 gen_set_label(end); 975 976 return; 977} 978 979 980/* 981 * Set the tail bytes of the strided loads/stores to 1: 982 * 983 * for (k = 0; k < nf; ++k) { 984 * cnt = (k * max_elems + vl) * esz; 985 * tot = (k * max_elems + max_elems) * esz; 986 * for (i = cnt; i < tot; i += esz) { 987 * store_1s(-1, vd[vl+i]); 988 * } 989 * } 990 */ 991static void gen_ldst_stride_tail_loop(DisasContext *s, TCGv dest, uint32_t nf, 992 gen_tl_ldst *st_fn) 993{ 994 TCGv i = tcg_temp_new(); 995 TCGv k = tcg_temp_new(); 996 TCGv tail_cnt = tcg_temp_new(); 997 TCGv tail_tot = tcg_temp_new(); 998 TCGv tail_addr = tcg_temp_new(); 999 1000 TCGLabel *start = gen_new_label(); 1001 TCGLabel *end = gen_new_label(); 1002 TCGLabel *start_i = gen_new_label(); 1003 TCGLabel *end_i = gen_new_label(); 1004 1005 uint32_t max_elems_b = MAXSZ(s); 1006 uint32_t esz = 1 << s->sew; 1007 1008 /* Start of the outer loop. */ 1009 tcg_gen_movi_tl(k, 0); 1010 tcg_gen_shli_tl(tail_cnt, cpu_vl, s->sew); 1011 tcg_gen_movi_tl(tail_tot, max_elems_b); 1012 tcg_gen_add_tl(tail_addr, dest, tail_cnt); 1013 gen_set_label(start); 1014 tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end); 1015 /* Start of the inner loop. */ 1016 tcg_gen_mov_tl(i, tail_cnt); 1017 gen_set_label(start_i); 1018 tcg_gen_brcond_tl(TCG_COND_GE, i, tail_tot, end_i); 1019 /* store_1s(-1, vd[vl+i]); */ 1020 st_fn(tcg_constant_tl(-1), (TCGv_ptr)tail_addr, 0); 1021 tcg_gen_addi_tl(tail_addr, tail_addr, esz); 1022 tcg_gen_addi_tl(i, i, esz); 1023 tcg_gen_br(start_i); 1024 /* End of the inner loop. */ 1025 gen_set_label(end_i); 1026 /* Update the counts */ 1027 tcg_gen_addi_tl(tail_cnt, tail_cnt, max_elems_b); 1028 tcg_gen_addi_tl(tail_tot, tail_cnt, max_elems_b); 1029 tcg_gen_addi_tl(k, k, 1); 1030 tcg_gen_br(start); 1031 /* End of the outer loop. */ 1032 gen_set_label(end); 1033 1034 return; 1035} 1036 1037static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, 1038 uint32_t data, DisasContext *s, bool is_load) 1039{ 1040 if (!s->vstart_eq_zero) { 1041 return false; 1042 } 1043 1044 TCGv dest = tcg_temp_new(); 1045 1046 uint32_t nf = FIELD_EX32(data, VDATA, NF); 1047 uint32_t vm = FIELD_EX32(data, VDATA, VM); 1048 1049 /* Destination register and mask register */ 1050 tcg_gen_addi_tl(dest, (TCGv)tcg_env, vreg_ofs(s, vd)); 1051 1052 /* 1053 * Select the appropriate load/tore to retrieve data from the vector 1054 * register given a specific sew. 1055 */ 1056 static gen_tl_ldst * const ld_fns[4] = { 1057 tcg_gen_ld8u_tl, tcg_gen_ld16u_tl, 1058 tcg_gen_ld32u_tl, tcg_gen_ld_tl 1059 }; 1060 1061 static gen_tl_ldst * const st_fns[4] = { 1062 tcg_gen_st8_tl, tcg_gen_st16_tl, 1063 tcg_gen_st32_tl, tcg_gen_st_tl 1064 }; 1065 1066 gen_tl_ldst *ld_fn = ld_fns[s->sew]; 1067 gen_tl_ldst *st_fn = st_fns[s->sew]; 1068 1069 if (ld_fn == NULL || st_fn == NULL) { 1070 return false; 1071 } 1072 1073 mark_vs_dirty(s); 1074 1075 gen_ldst_stride_main_loop(s, dest, rs1, rs2, vm, nf, ld_fn, st_fn, is_load); 1076 1077 tcg_gen_movi_tl(cpu_vstart, 0); 1078 1079 /* 1080 * Set the tail bytes to 1 if tail agnostic: 1081 */ 1082 if (s->vta != 0 && is_load) { 1083 gen_ldst_stride_tail_loop(s, dest, nf, st_fn); 1084 } 1085 1086 finalize_rvv_inst(s); 1087 return true; 1088} 1089 1090static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 1091{ 1092 uint32_t data = 0; 1093 1094 uint8_t emul = vext_get_emul(s, eew); 1095 data = FIELD_DP32(data, VDATA, VM, a->vm); 1096 data = FIELD_DP32(data, VDATA, LMUL, emul); 1097 data = FIELD_DP32(data, VDATA, NF, a->nf); 1098 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1099 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1100 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, true); 1101} 1102 1103static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 1104{ 1105 return require_rvv(s) && 1106 vext_check_isa_ill(s) && 1107 vext_check_load(s, a->rd, a->nf, a->vm, eew); 1108} 1109 1110GEN_VEXT_TRANS(vlse8_v, MO_8, rnfvm, ld_stride_op, ld_stride_check) 1111GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check) 1112GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check) 1113GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) 1114 1115static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 1116{ 1117 uint32_t data = 0; 1118 1119 uint8_t emul = vext_get_emul(s, eew); 1120 data = FIELD_DP32(data, VDATA, VM, a->vm); 1121 data = FIELD_DP32(data, VDATA, LMUL, emul); 1122 data = FIELD_DP32(data, VDATA, NF, a->nf); 1123 1124 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, false); 1125} 1126 1127static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 1128{ 1129 return require_rvv(s) && 1130 vext_check_isa_ill(s) && 1131 vext_check_store(s, a->rd, a->nf, eew); 1132} 1133 1134GEN_VEXT_TRANS(vsse8_v, MO_8, rnfvm, st_stride_op, st_stride_check) 1135GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check) 1136GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check) 1137GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check) 1138 1139/* 1140 *** index load and store 1141 */ 1142typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, 1143 TCGv_ptr, TCGv_env, TCGv_i32); 1144 1145static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 1146 uint32_t data, gen_helper_ldst_index *fn, 1147 DisasContext *s) 1148{ 1149 TCGv_ptr dest, mask, index; 1150 TCGv base; 1151 TCGv_i32 desc; 1152 1153 dest = tcg_temp_new_ptr(); 1154 mask = tcg_temp_new_ptr(); 1155 index = tcg_temp_new_ptr(); 1156 base = get_gpr(s, rs1, EXT_NONE); 1157 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1158 s->cfg_ptr->vlenb, data)); 1159 1160 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1161 tcg_gen_addi_ptr(index, tcg_env, vreg_ofs(s, vs2)); 1162 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1163 1164 mark_vs_dirty(s); 1165 1166 fn(dest, mask, base, index, tcg_env, desc); 1167 1168 finalize_rvv_inst(s); 1169 return true; 1170} 1171 1172static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 1173{ 1174 uint32_t data = 0; 1175 gen_helper_ldst_index *fn; 1176 static gen_helper_ldst_index * const fns[4][4] = { 1177 /* 1178 * offset vector register group EEW = 8, 1179 * data vector register group EEW = SEW 1180 */ 1181 { gen_helper_vlxei8_8_v, gen_helper_vlxei8_16_v, 1182 gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v }, 1183 /* 1184 * offset vector register group EEW = 16, 1185 * data vector register group EEW = SEW 1186 */ 1187 { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v, 1188 gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v }, 1189 /* 1190 * offset vector register group EEW = 32, 1191 * data vector register group EEW = SEW 1192 */ 1193 { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v, 1194 gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v }, 1195 /* 1196 * offset vector register group EEW = 64, 1197 * data vector register group EEW = SEW 1198 */ 1199 { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v, 1200 gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v } 1201 }; 1202 1203 fn = fns[eew][s->sew]; 1204 1205 uint8_t emul = vext_get_emul(s, s->sew); 1206 data = FIELD_DP32(data, VDATA, VM, a->vm); 1207 data = FIELD_DP32(data, VDATA, LMUL, emul); 1208 data = FIELD_DP32(data, VDATA, NF, a->nf); 1209 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1210 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1211 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); 1212} 1213 1214static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 1215{ 1216 return require_rvv(s) && 1217 vext_check_isa_ill(s) && 1218 vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); 1219} 1220 1221GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) 1222GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check) 1223GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check) 1224GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check) 1225 1226static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 1227{ 1228 uint32_t data = 0; 1229 gen_helper_ldst_index *fn; 1230 static gen_helper_ldst_index * const fns[4][4] = { 1231 /* 1232 * offset vector register group EEW = 8, 1233 * data vector register group EEW = SEW 1234 */ 1235 { gen_helper_vsxei8_8_v, gen_helper_vsxei8_16_v, 1236 gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v }, 1237 /* 1238 * offset vector register group EEW = 16, 1239 * data vector register group EEW = SEW 1240 */ 1241 { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v, 1242 gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v }, 1243 /* 1244 * offset vector register group EEW = 32, 1245 * data vector register group EEW = SEW 1246 */ 1247 { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v, 1248 gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v }, 1249 /* 1250 * offset vector register group EEW = 64, 1251 * data vector register group EEW = SEW 1252 */ 1253 { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v, 1254 gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v } 1255 }; 1256 1257 fn = fns[eew][s->sew]; 1258 1259 uint8_t emul = vext_get_emul(s, s->sew); 1260 data = FIELD_DP32(data, VDATA, VM, a->vm); 1261 data = FIELD_DP32(data, VDATA, LMUL, emul); 1262 data = FIELD_DP32(data, VDATA, NF, a->nf); 1263 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); 1264} 1265 1266static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 1267{ 1268 return require_rvv(s) && 1269 vext_check_isa_ill(s) && 1270 vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); 1271} 1272 1273GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) 1274GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check) 1275GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check) 1276GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check) 1277 1278/* 1279 *** unit stride fault-only-first load 1280 */ 1281static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, 1282 gen_helper_ldst_us *fn, DisasContext *s) 1283{ 1284 TCGv_ptr dest, mask; 1285 TCGv base; 1286 TCGv_i32 desc; 1287 1288 dest = tcg_temp_new_ptr(); 1289 mask = tcg_temp_new_ptr(); 1290 base = get_gpr(s, rs1, EXT_NONE); 1291 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1292 s->cfg_ptr->vlenb, data)); 1293 1294 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1295 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1296 1297 fn(dest, mask, base, tcg_env, desc); 1298 1299 finalize_rvv_inst(s); 1300 return true; 1301} 1302 1303static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 1304{ 1305 uint32_t data = 0; 1306 gen_helper_ldst_us *fn; 1307 static gen_helper_ldst_us * const fns[4] = { 1308 gen_helper_vle8ff_v, gen_helper_vle16ff_v, 1309 gen_helper_vle32ff_v, gen_helper_vle64ff_v 1310 }; 1311 1312 fn = fns[eew]; 1313 if (fn == NULL) { 1314 return false; 1315 } 1316 1317 uint8_t emul = vext_get_emul(s, eew); 1318 data = FIELD_DP32(data, VDATA, VM, a->vm); 1319 data = FIELD_DP32(data, VDATA, LMUL, emul); 1320 data = FIELD_DP32(data, VDATA, NF, a->nf); 1321 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1322 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1323 return ldff_trans(a->rd, a->rs1, data, fn, s); 1324} 1325 1326GEN_VEXT_TRANS(vle8ff_v, MO_8, r2nfvm, ldff_op, ld_us_check) 1327GEN_VEXT_TRANS(vle16ff_v, MO_16, r2nfvm, ldff_op, ld_us_check) 1328GEN_VEXT_TRANS(vle32ff_v, MO_32, r2nfvm, ldff_op, ld_us_check) 1329GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) 1330 1331/* 1332 * load and store whole register instructions 1333 */ 1334typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); 1335 1336static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, 1337 gen_helper_ldst_whole *fn, 1338 DisasContext *s) 1339{ 1340 TCGv_ptr dest; 1341 TCGv base; 1342 TCGv_i32 desc; 1343 1344 uint32_t data = FIELD_DP32(0, VDATA, NF, nf); 1345 data = FIELD_DP32(data, VDATA, VM, 1); 1346 dest = tcg_temp_new_ptr(); 1347 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1348 s->cfg_ptr->vlenb, data)); 1349 1350 base = get_gpr(s, rs1, EXT_NONE); 1351 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1352 1353 mark_vs_dirty(s); 1354 1355 fn(dest, base, tcg_env, desc); 1356 1357 finalize_rvv_inst(s); 1358 return true; 1359} 1360 1361/* 1362 * load and store whole register instructions ignore vtype and vl setting. 1363 * Thus, we don't need to check vill bit. (Section 7.9) 1364 */ 1365#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF) \ 1366static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 1367{ \ 1368 if (require_rvv(s) && \ 1369 QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ 1370 return ldst_whole_trans(a->rd, a->rs1, ARG_NF, \ 1371 gen_helper_##NAME, s); \ 1372 } \ 1373 return false; \ 1374} 1375 1376GEN_LDST_WHOLE_TRANS(vl1re8_v, 1) 1377GEN_LDST_WHOLE_TRANS(vl1re16_v, 1) 1378GEN_LDST_WHOLE_TRANS(vl1re32_v, 1) 1379GEN_LDST_WHOLE_TRANS(vl1re64_v, 1) 1380GEN_LDST_WHOLE_TRANS(vl2re8_v, 2) 1381GEN_LDST_WHOLE_TRANS(vl2re16_v, 2) 1382GEN_LDST_WHOLE_TRANS(vl2re32_v, 2) 1383GEN_LDST_WHOLE_TRANS(vl2re64_v, 2) 1384GEN_LDST_WHOLE_TRANS(vl4re8_v, 4) 1385GEN_LDST_WHOLE_TRANS(vl4re16_v, 4) 1386GEN_LDST_WHOLE_TRANS(vl4re32_v, 4) 1387GEN_LDST_WHOLE_TRANS(vl4re64_v, 4) 1388GEN_LDST_WHOLE_TRANS(vl8re8_v, 8) 1389GEN_LDST_WHOLE_TRANS(vl8re16_v, 8) 1390GEN_LDST_WHOLE_TRANS(vl8re32_v, 8) 1391GEN_LDST_WHOLE_TRANS(vl8re64_v, 8) 1392 1393/* 1394 * The vector whole register store instructions are encoded similar to 1395 * unmasked unit-stride store of elements with EEW=8. 1396 */ 1397GEN_LDST_WHOLE_TRANS(vs1r_v, 1) 1398GEN_LDST_WHOLE_TRANS(vs2r_v, 2) 1399GEN_LDST_WHOLE_TRANS(vs4r_v, 4) 1400GEN_LDST_WHOLE_TRANS(vs8r_v, 8) 1401 1402/* 1403 *** Vector Integer Arithmetic Instructions 1404 */ 1405 1406static bool opivv_check(DisasContext *s, arg_rmrr *a) 1407{ 1408 return require_rvv(s) && 1409 vext_check_isa_ill(s) && 1410 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1411} 1412 1413typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 1414 uint32_t, uint32_t, uint32_t); 1415 1416static inline bool 1417do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 1418 gen_helper_gvec_4_ptr *fn) 1419{ 1420 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1421 gvec_fn(s->sew, vreg_ofs(s, a->rd), 1422 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 1423 MAXSZ(s), MAXSZ(s)); 1424 } else { 1425 uint32_t data = 0; 1426 1427 data = FIELD_DP32(data, VDATA, VM, a->vm); 1428 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1429 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1430 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1431 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1432 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 1433 tcg_env, s->cfg_ptr->vlenb, 1434 s->cfg_ptr->vlenb, data, fn); 1435 } 1436 finalize_rvv_inst(s); 1437 return true; 1438} 1439 1440/* OPIVV with GVEC IR */ 1441#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 1442static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1443{ \ 1444 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1445 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1446 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1447 }; \ 1448 if (!opivv_check(s, a)) { \ 1449 return false; \ 1450 } \ 1451 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1452} 1453 1454GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 1455GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 1456 1457typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 1458 TCGv_env, TCGv_i32); 1459 1460static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 1461 gen_helper_opivx *fn, DisasContext *s) 1462{ 1463 TCGv_ptr dest, src2, mask; 1464 TCGv src1; 1465 TCGv_i32 desc; 1466 uint32_t data = 0; 1467 1468 dest = tcg_temp_new_ptr(); 1469 mask = tcg_temp_new_ptr(); 1470 src2 = tcg_temp_new_ptr(); 1471 src1 = get_gpr(s, rs1, EXT_SIGN); 1472 1473 data = FIELD_DP32(data, VDATA, VM, vm); 1474 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1475 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1476 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1477 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1478 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1479 s->cfg_ptr->vlenb, data)); 1480 1481 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1482 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 1483 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1484 1485 fn(dest, mask, src1, src2, tcg_env, desc); 1486 1487 finalize_rvv_inst(s); 1488 return true; 1489} 1490 1491static bool opivx_check(DisasContext *s, arg_rmrr *a) 1492{ 1493 return require_rvv(s) && 1494 vext_check_isa_ill(s) && 1495 vext_check_ss(s, a->rd, a->rs2, a->vm); 1496} 1497 1498typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 1499 uint32_t, uint32_t); 1500 1501static inline bool 1502do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 1503 gen_helper_opivx *fn) 1504{ 1505 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1506 TCGv_i64 src1 = tcg_temp_new_i64(); 1507 1508 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 1509 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1510 src1, MAXSZ(s), MAXSZ(s)); 1511 1512 finalize_rvv_inst(s); 1513 return true; 1514 } 1515 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1516} 1517 1518/* OPIVX with GVEC IR */ 1519#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 1520static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1521{ \ 1522 static gen_helper_opivx * const fns[4] = { \ 1523 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1524 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1525 }; \ 1526 if (!opivx_check(s, a)) { \ 1527 return false; \ 1528 } \ 1529 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1530} 1531 1532GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 1533GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 1534 1535static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1536{ 1537 tcg_gen_vec_sub8_i64(d, b, a); 1538} 1539 1540static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1541{ 1542 tcg_gen_vec_sub16_i64(d, b, a); 1543} 1544 1545static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 1546{ 1547 tcg_gen_sub_i32(ret, arg2, arg1); 1548} 1549 1550static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1551{ 1552 tcg_gen_sub_i64(ret, arg2, arg1); 1553} 1554 1555static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 1556{ 1557 tcg_gen_sub_vec(vece, r, b, a); 1558} 1559 1560static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 1561 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 1562{ 1563 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 1564 static const GVecGen2s rsub_op[4] = { 1565 { .fni8 = gen_vec_rsub8_i64, 1566 .fniv = gen_rsub_vec, 1567 .fno = gen_helper_vec_rsubs8, 1568 .opt_opc = vecop_list, 1569 .vece = MO_8 }, 1570 { .fni8 = gen_vec_rsub16_i64, 1571 .fniv = gen_rsub_vec, 1572 .fno = gen_helper_vec_rsubs16, 1573 .opt_opc = vecop_list, 1574 .vece = MO_16 }, 1575 { .fni4 = gen_rsub_i32, 1576 .fniv = gen_rsub_vec, 1577 .fno = gen_helper_vec_rsubs32, 1578 .opt_opc = vecop_list, 1579 .vece = MO_32 }, 1580 { .fni8 = gen_rsub_i64, 1581 .fniv = gen_rsub_vec, 1582 .fno = gen_helper_vec_rsubs64, 1583 .opt_opc = vecop_list, 1584 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 1585 .vece = MO_64 }, 1586 }; 1587 1588 tcg_debug_assert(vece <= MO_64); 1589 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 1590} 1591 1592GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 1593 1594typedef enum { 1595 IMM_ZX, /* Zero-extended */ 1596 IMM_SX, /* Sign-extended */ 1597 IMM_TRUNC_SEW, /* Truncate to log(SEW) bits */ 1598 IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */ 1599} imm_mode_t; 1600 1601static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode) 1602{ 1603 switch (imm_mode) { 1604 case IMM_ZX: 1605 return extract64(imm, 0, 5); 1606 case IMM_SX: 1607 return sextract64(imm, 0, 5); 1608 case IMM_TRUNC_SEW: 1609 return extract64(imm, 0, s->sew + 3); 1610 case IMM_TRUNC_2SEW: 1611 return extract64(imm, 0, s->sew + 4); 1612 default: 1613 g_assert_not_reached(); 1614 } 1615} 1616 1617static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 1618 gen_helper_opivx *fn, DisasContext *s, 1619 imm_mode_t imm_mode) 1620{ 1621 TCGv_ptr dest, src2, mask; 1622 TCGv src1; 1623 TCGv_i32 desc; 1624 uint32_t data = 0; 1625 1626 dest = tcg_temp_new_ptr(); 1627 mask = tcg_temp_new_ptr(); 1628 src2 = tcg_temp_new_ptr(); 1629 src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode)); 1630 1631 data = FIELD_DP32(data, VDATA, VM, vm); 1632 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1633 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1634 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1635 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1636 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1637 s->cfg_ptr->vlenb, data)); 1638 1639 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1640 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 1641 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1642 1643 fn(dest, mask, src1, src2, tcg_env, desc); 1644 1645 finalize_rvv_inst(s); 1646 return true; 1647} 1648 1649typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1650 uint32_t, uint32_t); 1651 1652static inline bool 1653do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1654 gen_helper_opivx *fn, imm_mode_t imm_mode) 1655{ 1656 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1657 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1658 extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); 1659 finalize_rvv_inst(s); 1660 return true; 1661 } 1662 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode); 1663} 1664 1665/* OPIVI with GVEC IR */ 1666#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \ 1667static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1668{ \ 1669 static gen_helper_opivx * const fns[4] = { \ 1670 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1671 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1672 }; \ 1673 if (!opivx_check(s, a)) { \ 1674 return false; \ 1675 } \ 1676 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1677 fns[s->sew], IMM_MODE); \ 1678} 1679 1680GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi) 1681 1682static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1683 int64_t c, uint32_t oprsz, uint32_t maxsz) 1684{ 1685 TCGv_i64 tmp = tcg_constant_i64(c); 1686 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1687} 1688 1689GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi) 1690 1691/* Vector Widening Integer Add/Subtract */ 1692 1693/* OPIVV with WIDEN */ 1694static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1695{ 1696 return require_rvv(s) && 1697 vext_check_isa_ill(s) && 1698 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 1699} 1700 1701static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1702 gen_helper_gvec_4_ptr *fn, 1703 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1704{ 1705 if (checkfn(s, a)) { 1706 uint32_t data = 0; 1707 1708 data = FIELD_DP32(data, VDATA, VM, a->vm); 1709 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1710 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1711 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1712 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1713 vreg_ofs(s, a->rs1), 1714 vreg_ofs(s, a->rs2), 1715 tcg_env, s->cfg_ptr->vlenb, 1716 s->cfg_ptr->vlenb, 1717 data, fn); 1718 finalize_rvv_inst(s); 1719 return true; 1720 } 1721 return false; 1722} 1723 1724#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1725static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1726{ \ 1727 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1728 gen_helper_##NAME##_b, \ 1729 gen_helper_##NAME##_h, \ 1730 gen_helper_##NAME##_w \ 1731 }; \ 1732 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1733} 1734 1735GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1736GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1737GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1738GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1739 1740/* OPIVX with WIDEN */ 1741static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1742{ 1743 return require_rvv(s) && 1744 vext_check_isa_ill(s) && 1745 vext_check_ds(s, a->rd, a->rs2, a->vm); 1746} 1747 1748#define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \ 1749static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1750{ \ 1751 if (CHECK(s, a)) { \ 1752 static gen_helper_opivx * const fns[3] = { \ 1753 gen_helper_##NAME##_b, \ 1754 gen_helper_##NAME##_h, \ 1755 gen_helper_##NAME##_w \ 1756 }; \ 1757 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); \ 1758 } \ 1759 return false; \ 1760} 1761 1762GEN_OPIVX_WIDEN_TRANS(vwaddu_vx, opivx_widen_check) 1763GEN_OPIVX_WIDEN_TRANS(vwadd_vx, opivx_widen_check) 1764GEN_OPIVX_WIDEN_TRANS(vwsubu_vx, opivx_widen_check) 1765GEN_OPIVX_WIDEN_TRANS(vwsub_vx, opivx_widen_check) 1766 1767/* WIDEN OPIVV with WIDEN */ 1768static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1769{ 1770 return require_rvv(s) && 1771 vext_check_isa_ill(s) && 1772 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 1773} 1774 1775static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1776 gen_helper_gvec_4_ptr *fn) 1777{ 1778 if (opiwv_widen_check(s, a)) { 1779 uint32_t data = 0; 1780 1781 data = FIELD_DP32(data, VDATA, VM, a->vm); 1782 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1783 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1784 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1785 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1786 vreg_ofs(s, a->rs1), 1787 vreg_ofs(s, a->rs2), 1788 tcg_env, s->cfg_ptr->vlenb, 1789 s->cfg_ptr->vlenb, data, fn); 1790 finalize_rvv_inst(s); 1791 return true; 1792 } 1793 return false; 1794} 1795 1796#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1797static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1798{ \ 1799 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1800 gen_helper_##NAME##_b, \ 1801 gen_helper_##NAME##_h, \ 1802 gen_helper_##NAME##_w \ 1803 }; \ 1804 return do_opiwv_widen(s, a, fns[s->sew]); \ 1805} 1806 1807GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1808GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1809GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1810GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1811 1812/* WIDEN OPIVX with WIDEN */ 1813static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1814{ 1815 return require_rvv(s) && 1816 vext_check_isa_ill(s) && 1817 vext_check_dd(s, a->rd, a->rs2, a->vm); 1818} 1819 1820static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1821 gen_helper_opivx *fn) 1822{ 1823 if (opiwx_widen_check(s, a)) { 1824 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1825 } 1826 return false; 1827} 1828 1829#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1830static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1831{ \ 1832 static gen_helper_opivx * const fns[3] = { \ 1833 gen_helper_##NAME##_b, \ 1834 gen_helper_##NAME##_h, \ 1835 gen_helper_##NAME##_w \ 1836 }; \ 1837 return do_opiwx_widen(s, a, fns[s->sew]); \ 1838} 1839 1840GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1841GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1842GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1843GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1844 1845static bool opivv_trans(uint32_t vd, uint32_t vs1, uint32_t vs2, uint32_t vm, 1846 gen_helper_gvec_4_ptr *fn, DisasContext *s) 1847{ 1848 uint32_t data = 0; 1849 1850 data = FIELD_DP32(data, VDATA, VM, vm); 1851 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1852 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1853 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1854 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1855 tcg_gen_gvec_4_ptr(vreg_ofs(s, vd), vreg_ofs(s, 0), vreg_ofs(s, vs1), 1856 vreg_ofs(s, vs2), tcg_env, s->cfg_ptr->vlenb, 1857 s->cfg_ptr->vlenb, data, fn); 1858 finalize_rvv_inst(s); 1859 return true; 1860} 1861 1862/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1863/* OPIVV without GVEC IR */ 1864#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1865static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1866{ \ 1867 if (CHECK(s, a)) { \ 1868 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1869 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1870 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1871 }; \ 1872 return opivv_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1873 } \ 1874 return false; \ 1875} 1876 1877/* 1878 * For vadc and vsbc, an illegal instruction exception is raised if the 1879 * destination vector register is v0 and LMUL > 1. (Section 11.4) 1880 */ 1881static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1882{ 1883 return require_rvv(s) && 1884 vext_check_isa_ill(s) && 1885 (a->rd != 0) && 1886 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1887} 1888 1889GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1890GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1891 1892/* 1893 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1894 * destination vector register overlaps a source vector register group. 1895 */ 1896static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1897{ 1898 return require_rvv(s) && 1899 vext_check_isa_ill(s) && 1900 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1901} 1902 1903GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1904GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1905 1906static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1907{ 1908 return require_rvv(s) && 1909 vext_check_isa_ill(s) && 1910 (a->rd != 0) && 1911 vext_check_ss(s, a->rd, a->rs2, a->vm); 1912} 1913 1914/* OPIVX without GVEC IR */ 1915#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1916static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1917{ \ 1918 if (CHECK(s, a)) { \ 1919 static gen_helper_opivx * const fns[4] = { \ 1920 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1921 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1922 }; \ 1923 \ 1924 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1925 } \ 1926 return false; \ 1927} 1928 1929GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1930GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1931 1932static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1933{ 1934 return require_rvv(s) && 1935 vext_check_isa_ill(s) && 1936 vext_check_ms(s, a->rd, a->rs2); 1937} 1938 1939GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1940GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1941 1942/* OPIVI without GVEC IR */ 1943#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK) \ 1944static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1945{ \ 1946 if (CHECK(s, a)) { \ 1947 static gen_helper_opivx * const fns[4] = { \ 1948 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1949 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1950 }; \ 1951 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1952 fns[s->sew], s, IMM_MODE); \ 1953 } \ 1954 return false; \ 1955} 1956 1957GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check) 1958GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check) 1959 1960/* Vector Bitwise Logical Instructions */ 1961GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1962GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1963GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1964GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1965GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1966GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1967GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi) 1968GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx, ori) 1969GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori) 1970 1971/* Vector Single-Width Bit Shift Instructions */ 1972GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1973GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1974GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1975 1976typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1977 uint32_t, uint32_t); 1978 1979static inline bool 1980do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1981 gen_helper_opivx *fn) 1982{ 1983 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1984 TCGv_i32 src1 = tcg_temp_new_i32(); 1985 1986 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1987 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1988 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1989 src1, MAXSZ(s), MAXSZ(s)); 1990 1991 finalize_rvv_inst(s); 1992 return true; 1993 } 1994 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1995} 1996 1997#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1998static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1999{ \ 2000 static gen_helper_opivx * const fns[4] = { \ 2001 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 2002 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 2003 }; \ 2004 if (!opivx_check(s, a)) { \ 2005 return false; \ 2006 } \ 2007 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 2008} 2009 2010GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 2011GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 2012GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 2013 2014GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_TRUNC_SEW, vsll_vx, shli) 2015GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_TRUNC_SEW, vsrl_vx, shri) 2016GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_TRUNC_SEW, vsra_vx, sari) 2017 2018/* Vector Narrowing Integer Right Shift Instructions */ 2019static bool opiwv_narrow_check(DisasContext *s, arg_rmrr *a) 2020{ 2021 return require_rvv(s) && 2022 vext_check_isa_ill(s) && 2023 vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm); 2024} 2025 2026/* OPIVV with NARROW */ 2027#define GEN_OPIWV_NARROW_TRANS(NAME) \ 2028static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2029{ \ 2030 if (opiwv_narrow_check(s, a)) { \ 2031 uint32_t data = 0; \ 2032 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2033 gen_helper_##NAME##_b, \ 2034 gen_helper_##NAME##_h, \ 2035 gen_helper_##NAME##_w, \ 2036 }; \ 2037 \ 2038 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2039 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2040 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2041 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2042 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2043 vreg_ofs(s, a->rs1), \ 2044 vreg_ofs(s, a->rs2), tcg_env, \ 2045 s->cfg_ptr->vlenb, \ 2046 s->cfg_ptr->vlenb, data, \ 2047 fns[s->sew]); \ 2048 finalize_rvv_inst(s); \ 2049 return true; \ 2050 } \ 2051 return false; \ 2052} 2053GEN_OPIWV_NARROW_TRANS(vnsra_wv) 2054GEN_OPIWV_NARROW_TRANS(vnsrl_wv) 2055 2056static bool opiwx_narrow_check(DisasContext *s, arg_rmrr *a) 2057{ 2058 return require_rvv(s) && 2059 vext_check_isa_ill(s) && 2060 vext_check_sd(s, a->rd, a->rs2, a->vm); 2061} 2062 2063/* OPIVX with NARROW */ 2064#define GEN_OPIWX_NARROW_TRANS(NAME) \ 2065static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2066{ \ 2067 if (opiwx_narrow_check(s, a)) { \ 2068 static gen_helper_opivx * const fns[3] = { \ 2069 gen_helper_##NAME##_b, \ 2070 gen_helper_##NAME##_h, \ 2071 gen_helper_##NAME##_w, \ 2072 }; \ 2073 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 2074 } \ 2075 return false; \ 2076} 2077 2078GEN_OPIWX_NARROW_TRANS(vnsra_wx) 2079GEN_OPIWX_NARROW_TRANS(vnsrl_wx) 2080 2081/* OPIWI with NARROW */ 2082#define GEN_OPIWI_NARROW_TRANS(NAME, IMM_MODE, OPIVX) \ 2083static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2084{ \ 2085 if (opiwx_narrow_check(s, a)) { \ 2086 static gen_helper_opivx * const fns[3] = { \ 2087 gen_helper_##OPIVX##_b, \ 2088 gen_helper_##OPIVX##_h, \ 2089 gen_helper_##OPIVX##_w, \ 2090 }; \ 2091 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 2092 fns[s->sew], s, IMM_MODE); \ 2093 } \ 2094 return false; \ 2095} 2096 2097GEN_OPIWI_NARROW_TRANS(vnsra_wi, IMM_ZX, vnsra_wx) 2098GEN_OPIWI_NARROW_TRANS(vnsrl_wi, IMM_ZX, vnsrl_wx) 2099 2100/* Vector Integer Comparison Instructions */ 2101/* 2102 * For all comparison instructions, an illegal instruction exception is raised 2103 * if the destination vector register overlaps a source vector register group 2104 * and LMUL > 1. 2105 */ 2106static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 2107{ 2108 return require_rvv(s) && 2109 vext_check_isa_ill(s) && 2110 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2111} 2112 2113GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 2114GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 2115GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 2116GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 2117GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 2118GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 2119 2120static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 2121{ 2122 return require_rvv(s) && 2123 vext_check_isa_ill(s) && 2124 vext_check_ms(s, a->rd, a->rs2); 2125} 2126 2127GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 2128GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 2129GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 2130GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 2131GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 2132GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 2133GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 2134GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 2135 2136GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check) 2137GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check) 2138GEN_OPIVI_TRANS(vmsleu_vi, IMM_SX, vmsleu_vx, opivx_cmp_check) 2139GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check) 2140GEN_OPIVI_TRANS(vmsgtu_vi, IMM_SX, vmsgtu_vx, opivx_cmp_check) 2141GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check) 2142 2143/* Vector Integer Min/Max Instructions */ 2144GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 2145GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 2146GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 2147GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 2148GEN_OPIVX_TRANS(vminu_vx, opivx_check) 2149GEN_OPIVX_TRANS(vmin_vx, opivx_check) 2150GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 2151GEN_OPIVX_TRANS(vmax_vx, opivx_check) 2152 2153/* Vector Single-Width Integer Multiply Instructions */ 2154 2155static bool vmulh_vv_check(DisasContext *s, arg_rmrr *a) 2156{ 2157 /* 2158 * All Zve* extensions support all vector integer instructions, 2159 * except that the vmulh integer multiply variants 2160 * that return the high word of the product 2161 * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) 2162 * are not included for EEW=64 in Zve64*. (Section 18.2) 2163 */ 2164 return opivv_check(s, a) && 2165 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2166} 2167 2168static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a) 2169{ 2170 /* 2171 * All Zve* extensions support all vector integer instructions, 2172 * except that the vmulh integer multiply variants 2173 * that return the high word of the product 2174 * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) 2175 * are not included for EEW=64 in Zve64*. (Section 18.2) 2176 */ 2177 return opivx_check(s, a) && 2178 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2179} 2180 2181GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 2182GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check) 2183GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check) 2184GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check) 2185GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 2186GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check) 2187GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check) 2188GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check) 2189 2190/* Vector Integer Divide Instructions */ 2191GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 2192GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 2193GEN_OPIVV_TRANS(vremu_vv, opivv_check) 2194GEN_OPIVV_TRANS(vrem_vv, opivv_check) 2195GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 2196GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 2197GEN_OPIVX_TRANS(vremu_vx, opivx_check) 2198GEN_OPIVX_TRANS(vrem_vx, opivx_check) 2199 2200/* Vector Widening Integer Multiply Instructions */ 2201GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 2202GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 2203GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 2204GEN_OPIVX_WIDEN_TRANS(vwmul_vx, opivx_widen_check) 2205GEN_OPIVX_WIDEN_TRANS(vwmulu_vx, opivx_widen_check) 2206GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx, opivx_widen_check) 2207 2208/* Vector Single-Width Integer Multiply-Add Instructions */ 2209GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 2210GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 2211GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 2212GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 2213GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 2214GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 2215GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 2216GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 2217 2218/* Vector Widening Integer Multiply-Add Instructions */ 2219GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 2220GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 2221GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 2222GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check) 2223GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check) 2224GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check) 2225GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check) 2226 2227/* Vector Integer Merge and Move Instructions */ 2228static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 2229{ 2230 if (require_rvv(s) && 2231 vext_check_isa_ill(s) && 2232 /* vmv.v.v has rs2 = 0 and vm = 1 */ 2233 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 2234 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2235 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 2236 vreg_ofs(s, a->rs1), 2237 MAXSZ(s), MAXSZ(s)); 2238 } else { 2239 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2240 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2241 static gen_helper_gvec_2_ptr * const fns[4] = { 2242 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 2243 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 2244 }; 2245 2246 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 2247 tcg_env, s->cfg_ptr->vlenb, 2248 s->cfg_ptr->vlenb, data, 2249 fns[s->sew]); 2250 } 2251 finalize_rvv_inst(s); 2252 return true; 2253 } 2254 return false; 2255} 2256 2257typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 2258static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 2259{ 2260 if (require_rvv(s) && 2261 vext_check_isa_ill(s) && 2262 /* vmv.v.x has rs2 = 0 and vm = 1 */ 2263 vext_check_ss(s, a->rd, 0, 1)) { 2264 TCGv s1; 2265 2266 s1 = get_gpr(s, a->rs1, EXT_SIGN); 2267 2268 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2269 if (get_xl(s) == MXL_RV32 && s->sew == MO_64) { 2270 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2271 tcg_gen_ext_tl_i64(s1_i64, s1); 2272 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2273 MAXSZ(s), MAXSZ(s), s1_i64); 2274 } else { 2275 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 2276 MAXSZ(s), MAXSZ(s), s1); 2277 } 2278 } else { 2279 TCGv_i32 desc; 2280 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2281 TCGv_ptr dest = tcg_temp_new_ptr(); 2282 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2283 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2284 static gen_helper_vmv_vx * const fns[4] = { 2285 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2286 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2287 }; 2288 2289 tcg_gen_ext_tl_i64(s1_i64, s1); 2290 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2291 s->cfg_ptr->vlenb, data)); 2292 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2293 fns[s->sew](dest, s1_i64, tcg_env, desc); 2294 } 2295 2296 finalize_rvv_inst(s); 2297 return true; 2298 } 2299 return false; 2300} 2301 2302static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 2303{ 2304 if (require_rvv(s) && 2305 vext_check_isa_ill(s) && 2306 /* vmv.v.i has rs2 = 0 and vm = 1 */ 2307 vext_check_ss(s, a->rd, 0, 1)) { 2308 int64_t simm = sextract64(a->rs1, 0, 5); 2309 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2310 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 2311 MAXSZ(s), MAXSZ(s), simm); 2312 } else { 2313 TCGv_i32 desc; 2314 TCGv_i64 s1; 2315 TCGv_ptr dest; 2316 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2317 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2318 static gen_helper_vmv_vx * const fns[4] = { 2319 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2320 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2321 }; 2322 2323 s1 = tcg_constant_i64(simm); 2324 dest = tcg_temp_new_ptr(); 2325 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2326 s->cfg_ptr->vlenb, data)); 2327 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2328 fns[s->sew](dest, s1, tcg_env, desc); 2329 } 2330 finalize_rvv_inst(s); 2331 return true; 2332 } 2333 return false; 2334} 2335 2336GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 2337GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 2338GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 2339 2340/* 2341 *** Vector Fixed-Point Arithmetic Instructions 2342 */ 2343 2344/* Vector Single-Width Saturating Add and Subtract */ 2345GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 2346GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 2347GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 2348GEN_OPIVV_TRANS(vssub_vv, opivv_check) 2349GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 2350GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 2351GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 2352GEN_OPIVX_TRANS(vssub_vx, opivx_check) 2353GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check) 2354GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 2355 2356/* Vector Single-Width Averaging Add and Subtract */ 2357GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 2358GEN_OPIVV_TRANS(vaaddu_vv, opivv_check) 2359GEN_OPIVV_TRANS(vasub_vv, opivv_check) 2360GEN_OPIVV_TRANS(vasubu_vv, opivv_check) 2361GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 2362GEN_OPIVX_TRANS(vaaddu_vx, opivx_check) 2363GEN_OPIVX_TRANS(vasub_vx, opivx_check) 2364GEN_OPIVX_TRANS(vasubu_vx, opivx_check) 2365 2366/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 2367 2368static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a) 2369{ 2370 /* 2371 * All Zve* extensions support all vector fixed-point arithmetic 2372 * instructions, except that vsmul.vv and vsmul.vx are not supported 2373 * for EEW=64 in Zve64*. (Section 18.2) 2374 */ 2375 return opivv_check(s, a) && 2376 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2377} 2378 2379static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a) 2380{ 2381 /* 2382 * All Zve* extensions support all vector fixed-point arithmetic 2383 * instructions, except that vsmul.vv and vsmul.vx are not supported 2384 * for EEW=64 in Zve64*. (Section 18.2) 2385 */ 2386 return opivx_check(s, a) && 2387 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2388} 2389 2390GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check) 2391GEN_OPIVX_TRANS(vsmul_vx, vsmul_vx_check) 2392 2393/* Vector Single-Width Scaling Shift Instructions */ 2394GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 2395GEN_OPIVV_TRANS(vssra_vv, opivv_check) 2396GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 2397GEN_OPIVX_TRANS(vssra_vx, opivx_check) 2398GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check) 2399GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check) 2400 2401/* Vector Narrowing Fixed-Point Clip Instructions */ 2402GEN_OPIWV_NARROW_TRANS(vnclipu_wv) 2403GEN_OPIWV_NARROW_TRANS(vnclip_wv) 2404GEN_OPIWX_NARROW_TRANS(vnclipu_wx) 2405GEN_OPIWX_NARROW_TRANS(vnclip_wx) 2406GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx) 2407GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx) 2408 2409/* 2410 *** Vector Float Point Arithmetic Instructions 2411 */ 2412 2413/* 2414 * As RVF-only cpus always have values NaN-boxed to 64-bits, 2415 * RVF and RVD can be treated equally. 2416 * We don't have to deal with the cases of: SEW > FLEN. 2417 * 2418 * If SEW < FLEN, check whether input fp register is a valid 2419 * NaN-boxed value, in which case the least-significant SEW bits 2420 * of the f register are used, else the canonical NaN value is used. 2421 */ 2422static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 2423{ 2424 switch (s->sew) { 2425 case 1: 2426 gen_check_nanbox_h(out, in); 2427 break; 2428 case 2: 2429 gen_check_nanbox_s(out, in); 2430 break; 2431 case 3: 2432 tcg_gen_mov_i64(out, in); 2433 break; 2434 default: 2435 g_assert_not_reached(); 2436 } 2437} 2438 2439/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 2440 2441/* 2442 * If the current SEW does not correspond to a supported IEEE floating-point 2443 * type, an illegal instruction exception is raised. 2444 */ 2445static bool opfvv_check(DisasContext *s, arg_rmrr *a) 2446{ 2447 return require_rvv(s) && 2448 require_rvf(s) && 2449 vext_check_isa_ill(s) && 2450 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2451} 2452 2453/* OPFVV without GVEC IR */ 2454#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2455static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2456{ \ 2457 if (CHECK(s, a)) { \ 2458 uint32_t data = 0; \ 2459 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2460 gen_helper_##NAME##_h, \ 2461 gen_helper_##NAME##_w, \ 2462 gen_helper_##NAME##_d, \ 2463 }; \ 2464 gen_set_rm(s, RISCV_FRM_DYN); \ 2465 \ 2466 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2467 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2468 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2469 data = \ 2470 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 2471 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2472 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2473 vreg_ofs(s, a->rs1), \ 2474 vreg_ofs(s, a->rs2), tcg_env, \ 2475 s->cfg_ptr->vlenb, \ 2476 s->cfg_ptr->vlenb, data, \ 2477 fns[s->sew - 1]); \ 2478 finalize_rvv_inst(s); \ 2479 return true; \ 2480 } \ 2481 return false; \ 2482} 2483GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2484GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2485 2486typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2487 TCGv_env, TCGv_i32); 2488 2489static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2490 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2491{ 2492 TCGv_ptr dest, src2, mask; 2493 TCGv_i32 desc; 2494 TCGv_i64 t1; 2495 2496 dest = tcg_temp_new_ptr(); 2497 mask = tcg_temp_new_ptr(); 2498 src2 = tcg_temp_new_ptr(); 2499 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2500 s->cfg_ptr->vlenb, data)); 2501 2502 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 2503 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 2504 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 2505 2506 /* NaN-box f[rs1] */ 2507 t1 = tcg_temp_new_i64(); 2508 do_nanbox(s, t1, cpu_fpr[rs1]); 2509 2510 fn(dest, mask, t1, src2, tcg_env, desc); 2511 2512 finalize_rvv_inst(s); 2513 return true; 2514} 2515 2516/* 2517 * If the current SEW does not correspond to a supported IEEE floating-point 2518 * type, an illegal instruction exception is raised 2519 */ 2520static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2521{ 2522 return require_rvv(s) && 2523 require_rvf(s) && 2524 vext_check_isa_ill(s) && 2525 vext_check_ss(s, a->rd, a->rs2, a->vm); 2526} 2527 2528/* OPFVF without GVEC IR */ 2529#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2530static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2531{ \ 2532 if (CHECK(s, a)) { \ 2533 uint32_t data = 0; \ 2534 static gen_helper_opfvf *const fns[3] = { \ 2535 gen_helper_##NAME##_h, \ 2536 gen_helper_##NAME##_w, \ 2537 gen_helper_##NAME##_d, \ 2538 }; \ 2539 gen_set_rm(s, RISCV_FRM_DYN); \ 2540 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2541 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2542 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2543 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \ 2544 s->cfg_vta_all_1s); \ 2545 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2546 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2547 fns[s->sew - 1], s); \ 2548 } \ 2549 return false; \ 2550} 2551 2552GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2553GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2554GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2555 2556/* Vector Widening Floating-Point Add/Subtract Instructions */ 2557static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2558{ 2559 return require_rvv(s) && 2560 require_rvf(s) && 2561 require_scale_rvf(s) && 2562 vext_check_isa_ill(s) && 2563 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2564} 2565 2566/* OPFVV with WIDEN */ 2567#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2568static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2569{ \ 2570 if (CHECK(s, a)) { \ 2571 uint32_t data = 0; \ 2572 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2573 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2574 }; \ 2575 gen_set_rm(s, RISCV_FRM_DYN); \ 2576 \ 2577 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2578 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2579 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2580 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2581 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2582 vreg_ofs(s, a->rs1), \ 2583 vreg_ofs(s, a->rs2), tcg_env, \ 2584 s->cfg_ptr->vlenb, \ 2585 s->cfg_ptr->vlenb, data, \ 2586 fns[s->sew - 1]); \ 2587 finalize_rvv_inst(s); \ 2588 return true; \ 2589 } \ 2590 return false; \ 2591} 2592 2593GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2594GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2595 2596static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2597{ 2598 return require_rvv(s) && 2599 require_rvf(s) && 2600 require_scale_rvf(s) && 2601 vext_check_isa_ill(s) && 2602 vext_check_ds(s, a->rd, a->rs2, a->vm); 2603} 2604 2605/* OPFVF with WIDEN */ 2606#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2607static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2608{ \ 2609 if (opfvf_widen_check(s, a)) { \ 2610 uint32_t data = 0; \ 2611 static gen_helper_opfvf *const fns[2] = { \ 2612 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2613 }; \ 2614 gen_set_rm(s, RISCV_FRM_DYN); \ 2615 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2616 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2617 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2618 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2619 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2620 fns[s->sew - 1], s); \ 2621 } \ 2622 return false; \ 2623} 2624 2625GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2626GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2627 2628static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2629{ 2630 return require_rvv(s) && 2631 require_rvf(s) && 2632 require_scale_rvf(s) && 2633 vext_check_isa_ill(s) && 2634 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2635} 2636 2637/* WIDEN OPFVV with WIDEN */ 2638#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2639static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2640{ \ 2641 if (opfwv_widen_check(s, a)) { \ 2642 uint32_t data = 0; \ 2643 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2644 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2645 }; \ 2646 gen_set_rm(s, RISCV_FRM_DYN); \ 2647 \ 2648 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2649 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2650 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2651 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2652 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2653 vreg_ofs(s, a->rs1), \ 2654 vreg_ofs(s, a->rs2), tcg_env, \ 2655 s->cfg_ptr->vlenb, \ 2656 s->cfg_ptr->vlenb, data, \ 2657 fns[s->sew - 1]); \ 2658 finalize_rvv_inst(s); \ 2659 return true; \ 2660 } \ 2661 return false; \ 2662} 2663 2664GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2665GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2666 2667static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2668{ 2669 return require_rvv(s) && 2670 require_rvf(s) && 2671 require_scale_rvf(s) && 2672 vext_check_isa_ill(s) && 2673 vext_check_dd(s, a->rd, a->rs2, a->vm); 2674} 2675 2676/* WIDEN OPFVF with WIDEN */ 2677#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2678static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2679{ \ 2680 if (opfwf_widen_check(s, a)) { \ 2681 uint32_t data = 0; \ 2682 static gen_helper_opfvf *const fns[2] = { \ 2683 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2684 }; \ 2685 gen_set_rm(s, RISCV_FRM_DYN); \ 2686 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2687 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2688 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2689 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2690 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2691 fns[s->sew - 1], s); \ 2692 } \ 2693 return false; \ 2694} 2695 2696GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2697GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2698 2699/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2700GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2701GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2702GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2703GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2704GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2705 2706/* Vector Widening Floating-Point Multiply */ 2707GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2708GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2709 2710/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2711GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2712GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2713GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2714GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2715GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2716GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2717GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2718GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2719GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2720GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2721GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2722GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2723GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2724GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2725GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2726GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2727 2728/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2729GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2730GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2731GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2732GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2733GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2734GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2735GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2736GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2737 2738/* Vector Floating-Point Square-Root Instruction */ 2739 2740/* 2741 * If the current SEW does not correspond to a supported IEEE floating-point 2742 * type, an illegal instruction exception is raised 2743 */ 2744static bool opfv_check(DisasContext *s, arg_rmr *a) 2745{ 2746 return require_rvv(s) && 2747 require_rvf(s) && 2748 vext_check_isa_ill(s) && 2749 /* OPFV instructions ignore vs1 check */ 2750 vext_check_ss(s, a->rd, a->rs2, a->vm); 2751} 2752 2753static bool do_opfv(DisasContext *s, arg_rmr *a, 2754 gen_helper_gvec_3_ptr *fn, 2755 bool (*checkfn)(DisasContext *, arg_rmr *), 2756 int rm) 2757{ 2758 if (checkfn(s, a)) { 2759 uint32_t data = 0; 2760 gen_set_rm_chkfrm(s, rm); 2761 2762 data = FIELD_DP32(data, VDATA, VM, a->vm); 2763 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2764 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2765 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2766 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2767 vreg_ofs(s, a->rs2), tcg_env, 2768 s->cfg_ptr->vlenb, 2769 s->cfg_ptr->vlenb, data, fn); 2770 finalize_rvv_inst(s); 2771 return true; 2772 } 2773 return false; 2774} 2775 2776#define GEN_OPFV_TRANS(NAME, CHECK, FRM) \ 2777static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2778{ \ 2779 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2780 gen_helper_##NAME##_h, \ 2781 gen_helper_##NAME##_w, \ 2782 gen_helper_##NAME##_d \ 2783 }; \ 2784 return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \ 2785} 2786 2787GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN) 2788GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN) 2789GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN) 2790 2791/* Vector Floating-Point MIN/MAX Instructions */ 2792GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2793GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2794GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2795GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2796 2797/* Vector Floating-Point Sign-Injection Instructions */ 2798GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2799GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2800GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2801GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2802GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2803GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2804 2805/* Vector Floating-Point Compare Instructions */ 2806static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2807{ 2808 return require_rvv(s) && 2809 require_rvf(s) && 2810 vext_check_isa_ill(s) && 2811 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2812} 2813 2814GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2815GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2816GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2817GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2818 2819static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2820{ 2821 return require_rvv(s) && 2822 require_rvf(s) && 2823 vext_check_isa_ill(s) && 2824 vext_check_ms(s, a->rd, a->rs2); 2825} 2826 2827GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2828GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2829GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2830GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2831GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2832GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2833 2834/* Vector Floating-Point Classify Instruction */ 2835GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN) 2836 2837/* Vector Floating-Point Merge Instruction */ 2838GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2839 2840static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2841{ 2842 if (require_rvv(s) && 2843 require_rvf(s) && 2844 vext_check_isa_ill(s) && 2845 require_align(a->rd, s->lmul)) { 2846 gen_set_rm(s, RISCV_FRM_DYN); 2847 2848 TCGv_i64 t1; 2849 2850 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2851 t1 = tcg_temp_new_i64(); 2852 /* NaN-box f[rs1] */ 2853 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2854 2855 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2856 MAXSZ(s), MAXSZ(s), t1); 2857 } else { 2858 TCGv_ptr dest; 2859 TCGv_i32 desc; 2860 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2861 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2862 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2863 static gen_helper_vmv_vx * const fns[3] = { 2864 gen_helper_vmv_v_x_h, 2865 gen_helper_vmv_v_x_w, 2866 gen_helper_vmv_v_x_d, 2867 }; 2868 2869 t1 = tcg_temp_new_i64(); 2870 /* NaN-box f[rs1] */ 2871 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2872 2873 dest = tcg_temp_new_ptr(); 2874 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2875 s->cfg_ptr->vlenb, data)); 2876 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2877 2878 fns[s->sew - 1](dest, t1, tcg_env, desc); 2879 } 2880 finalize_rvv_inst(s); 2881 return true; 2882 } 2883 return false; 2884} 2885 2886/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2887#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM) \ 2888static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2889{ \ 2890 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2891 gen_helper_##HELPER##_h, \ 2892 gen_helper_##HELPER##_w, \ 2893 gen_helper_##HELPER##_d \ 2894 }; \ 2895 return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \ 2896} 2897 2898GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN) 2899GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN) 2900GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN) 2901GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN) 2902/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */ 2903GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ) 2904GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ) 2905 2906/* Widening Floating-Point/Integer Type-Convert Instructions */ 2907 2908/* 2909 * If the current SEW does not correspond to a supported IEEE floating-point 2910 * type, an illegal instruction exception is raised 2911 */ 2912static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2913{ 2914 return require_rvv(s) && 2915 vext_check_isa_ill(s) && 2916 vext_check_ds(s, a->rd, a->rs2, a->vm); 2917} 2918 2919static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) 2920{ 2921 return opfv_widen_check(s, a) && 2922 require_rvf(s); 2923} 2924 2925static bool opffv_widen_check(DisasContext *s, arg_rmr *a) 2926{ 2927 return opfv_widen_check(s, a) && 2928 require_rvfmin(s) && 2929 require_scale_rvfmin(s); 2930} 2931 2932#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ 2933static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2934{ \ 2935 if (CHECK(s, a)) { \ 2936 uint32_t data = 0; \ 2937 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2938 gen_helper_##HELPER##_h, \ 2939 gen_helper_##HELPER##_w, \ 2940 }; \ 2941 gen_set_rm_chkfrm(s, FRM); \ 2942 \ 2943 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2944 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2945 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2946 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2947 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2948 vreg_ofs(s, a->rs2), tcg_env, \ 2949 s->cfg_ptr->vlenb, \ 2950 s->cfg_ptr->vlenb, data, \ 2951 fns[s->sew - 1]); \ 2952 finalize_rvv_inst(s); \ 2953 return true; \ 2954 } \ 2955 return false; \ 2956} 2957 2958GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2959 RISCV_FRM_DYN) 2960GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2961 RISCV_FRM_DYN) 2962GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v, 2963 RISCV_FRM_DYN) 2964/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2965GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2966 RISCV_FRM_RTZ) 2967GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2968 RISCV_FRM_RTZ) 2969 2970static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2971{ 2972 return require_rvv(s) && 2973 require_scale_rvf(s) && 2974 vext_check_isa_ill(s) && 2975 /* OPFV widening instructions ignore vs1 check */ 2976 vext_check_ds(s, a->rd, a->rs2, a->vm); 2977} 2978 2979#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2980static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2981{ \ 2982 if (opfxv_widen_check(s, a)) { \ 2983 uint32_t data = 0; \ 2984 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2985 gen_helper_##NAME##_b, \ 2986 gen_helper_##NAME##_h, \ 2987 gen_helper_##NAME##_w, \ 2988 }; \ 2989 gen_set_rm(s, RISCV_FRM_DYN); \ 2990 \ 2991 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2992 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2993 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2994 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2995 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2996 vreg_ofs(s, a->rs2), tcg_env, \ 2997 s->cfg_ptr->vlenb, \ 2998 s->cfg_ptr->vlenb, data, \ 2999 fns[s->sew]); \ 3000 finalize_rvv_inst(s); \ 3001 return true; \ 3002 } \ 3003 return false; \ 3004} 3005 3006GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 3007GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 3008 3009/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 3010 3011/* 3012 * If the current SEW does not correspond to a supported IEEE floating-point 3013 * type, an illegal instruction exception is raised 3014 */ 3015static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 3016{ 3017 return require_rvv(s) && 3018 vext_check_isa_ill(s) && 3019 /* OPFV narrowing instructions ignore vs1 check */ 3020 vext_check_sd(s, a->rd, a->rs2, a->vm); 3021} 3022 3023static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) 3024{ 3025 return opfv_narrow_check(s, a) && 3026 require_rvf(s) && 3027 (s->sew != MO_64); 3028} 3029 3030static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) 3031{ 3032 return opfv_narrow_check(s, a) && 3033 require_rvfmin(s) && 3034 require_scale_rvfmin(s); 3035} 3036 3037static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a) 3038{ 3039 return opfv_narrow_check(s, a) && 3040 require_rvf(s) && 3041 require_scale_rvf(s); 3042} 3043 3044#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ 3045static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3046{ \ 3047 if (CHECK(s, a)) { \ 3048 uint32_t data = 0; \ 3049 static gen_helper_gvec_3_ptr * const fns[2] = { \ 3050 gen_helper_##HELPER##_h, \ 3051 gen_helper_##HELPER##_w, \ 3052 }; \ 3053 gen_set_rm_chkfrm(s, FRM); \ 3054 \ 3055 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3056 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3057 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 3058 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3059 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 3060 vreg_ofs(s, a->rs2), tcg_env, \ 3061 s->cfg_ptr->vlenb, \ 3062 s->cfg_ptr->vlenb, data, \ 3063 fns[s->sew - 1]); \ 3064 finalize_rvv_inst(s); \ 3065 return true; \ 3066 } \ 3067 return false; \ 3068} 3069 3070GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w, 3071 RISCV_FRM_DYN) 3072GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w, 3073 RISCV_FRM_DYN) 3074GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 3075 RISCV_FRM_DYN) 3076/* Reuse the helper function from vfncvt.f.f.w */ 3077GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_rod_narrow_check, vfncvt_f_f_w, 3078 RISCV_FRM_ROD) 3079 3080static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 3081{ 3082 return require_rvv(s) && 3083 require_scale_rvf(s) && 3084 vext_check_isa_ill(s) && 3085 /* OPFV narrowing instructions ignore vs1 check */ 3086 vext_check_sd(s, a->rd, a->rs2, a->vm); 3087} 3088 3089#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 3090static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3091{ \ 3092 if (opxfv_narrow_check(s, a)) { \ 3093 uint32_t data = 0; \ 3094 static gen_helper_gvec_3_ptr * const fns[3] = { \ 3095 gen_helper_##HELPER##_b, \ 3096 gen_helper_##HELPER##_h, \ 3097 gen_helper_##HELPER##_w, \ 3098 }; \ 3099 gen_set_rm_chkfrm(s, FRM); \ 3100 \ 3101 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3102 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3103 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 3104 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3105 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 3106 vreg_ofs(s, a->rs2), tcg_env, \ 3107 s->cfg_ptr->vlenb, \ 3108 s->cfg_ptr->vlenb, data, \ 3109 fns[s->sew]); \ 3110 finalize_rvv_inst(s); \ 3111 return true; \ 3112 } \ 3113 return false; \ 3114} 3115 3116GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 3117GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 3118/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 3119GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 3120GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 3121 3122/* 3123 *** Vector Reduction Operations 3124 */ 3125/* Vector Single-Width Integer Reduction Instructions */ 3126static bool reduction_check(DisasContext *s, arg_rmrr *a) 3127{ 3128 return require_rvv(s) && 3129 vext_check_isa_ill(s) && 3130 vext_check_reduction(s, a->rs2); 3131} 3132 3133GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 3134GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 3135GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 3136GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 3137GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 3138GEN_OPIVV_TRANS(vredand_vs, reduction_check) 3139GEN_OPIVV_TRANS(vredor_vs, reduction_check) 3140GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 3141 3142/* Vector Widening Integer Reduction Instructions */ 3143static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 3144{ 3145 return reduction_check(s, a) && (s->sew < MO_64) && 3146 ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)); 3147} 3148 3149GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 3150GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 3151 3152/* Vector Single-Width Floating-Point Reduction Instructions */ 3153static bool freduction_check(DisasContext *s, arg_rmrr *a) 3154{ 3155 return reduction_check(s, a) && 3156 require_rvf(s); 3157} 3158 3159GEN_OPFVV_TRANS(vfredusum_vs, freduction_check) 3160GEN_OPFVV_TRANS(vfredosum_vs, freduction_check) 3161GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 3162GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 3163 3164/* Vector Widening Floating-Point Reduction Instructions */ 3165static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 3166{ 3167 return reduction_widen_check(s, a) && 3168 require_rvf(s) && 3169 require_scale_rvf(s); 3170} 3171 3172GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) 3173GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check) 3174 3175/* 3176 *** Vector Mask Operations 3177 */ 3178 3179/* Vector Mask-Register Logical Instructions */ 3180#define GEN_MM_TRANS(NAME) \ 3181static bool trans_##NAME(DisasContext *s, arg_r *a) \ 3182{ \ 3183 if (require_rvv(s) && \ 3184 vext_check_isa_ill(s)) { \ 3185 uint32_t data = 0; \ 3186 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 3187 \ 3188 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3189 data = \ 3190 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 3191 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 3192 vreg_ofs(s, a->rs1), \ 3193 vreg_ofs(s, a->rs2), tcg_env, \ 3194 s->cfg_ptr->vlenb, \ 3195 s->cfg_ptr->vlenb, data, fn); \ 3196 finalize_rvv_inst(s); \ 3197 return true; \ 3198 } \ 3199 return false; \ 3200} 3201 3202GEN_MM_TRANS(vmand_mm) 3203GEN_MM_TRANS(vmnand_mm) 3204GEN_MM_TRANS(vmandn_mm) 3205GEN_MM_TRANS(vmxor_mm) 3206GEN_MM_TRANS(vmor_mm) 3207GEN_MM_TRANS(vmnor_mm) 3208GEN_MM_TRANS(vmorn_mm) 3209GEN_MM_TRANS(vmxnor_mm) 3210 3211/* Vector count population in mask vcpop */ 3212static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 3213{ 3214 if (require_rvv(s) && 3215 vext_check_isa_ill(s) && 3216 s->vstart_eq_zero) { 3217 TCGv_ptr src2, mask; 3218 TCGv dst; 3219 TCGv_i32 desc; 3220 uint32_t data = 0; 3221 data = FIELD_DP32(data, VDATA, VM, a->vm); 3222 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3223 3224 mask = tcg_temp_new_ptr(); 3225 src2 = tcg_temp_new_ptr(); 3226 dst = dest_gpr(s, a->rd); 3227 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 3228 s->cfg_ptr->vlenb, data)); 3229 3230 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); 3231 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 3232 3233 gen_helper_vcpop_m(dst, mask, src2, tcg_env, desc); 3234 gen_set_gpr(s, a->rd, dst); 3235 return true; 3236 } 3237 return false; 3238} 3239 3240/* vmfirst find-first-set mask bit */ 3241static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 3242{ 3243 if (require_rvv(s) && 3244 vext_check_isa_ill(s) && 3245 s->vstart_eq_zero) { 3246 TCGv_ptr src2, mask; 3247 TCGv dst; 3248 TCGv_i32 desc; 3249 uint32_t data = 0; 3250 data = FIELD_DP32(data, VDATA, VM, a->vm); 3251 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3252 3253 mask = tcg_temp_new_ptr(); 3254 src2 = tcg_temp_new_ptr(); 3255 dst = dest_gpr(s, a->rd); 3256 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 3257 s->cfg_ptr->vlenb, data)); 3258 3259 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); 3260 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 3261 3262 gen_helper_vfirst_m(dst, mask, src2, tcg_env, desc); 3263 gen_set_gpr(s, a->rd, dst); 3264 return true; 3265 } 3266 return false; 3267} 3268 3269/* 3270 * vmsbf.m set-before-first mask bit 3271 * vmsif.m set-including-first mask bit 3272 * vmsof.m set-only-first mask bit 3273 */ 3274#define GEN_M_TRANS(NAME) \ 3275static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3276{ \ 3277 if (require_rvv(s) && \ 3278 vext_check_isa_ill(s) && \ 3279 require_vm(a->vm, a->rd) && \ 3280 (a->rd != a->rs2) && \ 3281 s->vstart_eq_zero) { \ 3282 uint32_t data = 0; \ 3283 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 3284 \ 3285 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3286 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3287 data = \ 3288 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 3289 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3290 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 3291 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 3292 tcg_env, s->cfg_ptr->vlenb, \ 3293 s->cfg_ptr->vlenb, \ 3294 data, fn); \ 3295 finalize_rvv_inst(s); \ 3296 return true; \ 3297 } \ 3298 return false; \ 3299} 3300 3301GEN_M_TRANS(vmsbf_m) 3302GEN_M_TRANS(vmsif_m) 3303GEN_M_TRANS(vmsof_m) 3304 3305/* 3306 * Vector Iota Instruction 3307 * 3308 * 1. The destination register cannot overlap the source register. 3309 * 2. If masked, cannot overlap the mask register ('v0'). 3310 * 3. An illegal instruction exception is raised if vstart is non-zero. 3311 */ 3312static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 3313{ 3314 if (require_rvv(s) && 3315 vext_check_isa_ill(s) && 3316 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 3317 require_vm(a->vm, a->rd) && 3318 require_align(a->rd, s->lmul) && 3319 s->vstart_eq_zero) { 3320 uint32_t data = 0; 3321 3322 data = FIELD_DP32(data, VDATA, VM, a->vm); 3323 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3324 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3325 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3326 static gen_helper_gvec_3_ptr * const fns[4] = { 3327 gen_helper_viota_m_b, gen_helper_viota_m_h, 3328 gen_helper_viota_m_w, gen_helper_viota_m_d, 3329 }; 3330 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3331 vreg_ofs(s, a->rs2), tcg_env, 3332 s->cfg_ptr->vlenb, 3333 s->cfg_ptr->vlenb, data, fns[s->sew]); 3334 finalize_rvv_inst(s); 3335 return true; 3336 } 3337 return false; 3338} 3339 3340/* Vector Element Index Instruction */ 3341static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3342{ 3343 if (require_rvv(s) && 3344 vext_check_isa_ill(s) && 3345 require_align(a->rd, s->lmul) && 3346 require_vm(a->vm, a->rd)) { 3347 uint32_t data = 0; 3348 3349 data = FIELD_DP32(data, VDATA, VM, a->vm); 3350 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3351 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3352 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3353 static gen_helper_gvec_2_ptr * const fns[4] = { 3354 gen_helper_vid_v_b, gen_helper_vid_v_h, 3355 gen_helper_vid_v_w, gen_helper_vid_v_d, 3356 }; 3357 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3358 tcg_env, s->cfg_ptr->vlenb, 3359 s->cfg_ptr->vlenb, 3360 data, fns[s->sew]); 3361 finalize_rvv_inst(s); 3362 return true; 3363 } 3364 return false; 3365} 3366 3367/* 3368 *** Vector Permutation Instructions 3369 */ 3370 3371static void load_element(TCGv_i64 dest, TCGv_ptr base, 3372 int ofs, int sew, bool sign) 3373{ 3374 switch (sew) { 3375 case MO_8: 3376 if (!sign) { 3377 tcg_gen_ld8u_i64(dest, base, ofs); 3378 } else { 3379 tcg_gen_ld8s_i64(dest, base, ofs); 3380 } 3381 break; 3382 case MO_16: 3383 if (!sign) { 3384 tcg_gen_ld16u_i64(dest, base, ofs); 3385 } else { 3386 tcg_gen_ld16s_i64(dest, base, ofs); 3387 } 3388 break; 3389 case MO_32: 3390 if (!sign) { 3391 tcg_gen_ld32u_i64(dest, base, ofs); 3392 } else { 3393 tcg_gen_ld32s_i64(dest, base, ofs); 3394 } 3395 break; 3396 case MO_64: 3397 tcg_gen_ld_i64(dest, base, ofs); 3398 break; 3399 default: 3400 g_assert_not_reached(); 3401 } 3402} 3403 3404/* offset of the idx element with base register r */ 3405static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3406{ 3407#if HOST_BIG_ENDIAN 3408 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3409#else 3410 return vreg_ofs(s, r) + (idx << s->sew); 3411#endif 3412} 3413 3414/* adjust the index according to the endian */ 3415static void endian_adjust(TCGv_i32 ofs, int sew) 3416{ 3417#if HOST_BIG_ENDIAN 3418 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3419#endif 3420} 3421 3422/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3423static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3424 int vreg, TCGv idx, int vlmax) 3425{ 3426 TCGv_i32 ofs = tcg_temp_new_i32(); 3427 TCGv_ptr base = tcg_temp_new_ptr(); 3428 TCGv_i64 t_idx = tcg_temp_new_i64(); 3429 TCGv_i64 t_vlmax, t_zero; 3430 3431 /* 3432 * Mask the index to the length so that we do 3433 * not produce an out-of-range load. 3434 */ 3435 tcg_gen_trunc_tl_i32(ofs, idx); 3436 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3437 3438 /* Convert the index to an offset. */ 3439 endian_adjust(ofs, s->sew); 3440 tcg_gen_shli_i32(ofs, ofs, s->sew); 3441 3442 /* Convert the index to a pointer. */ 3443 tcg_gen_ext_i32_ptr(base, ofs); 3444 tcg_gen_add_ptr(base, base, tcg_env); 3445 3446 /* Perform the load. */ 3447 load_element(dest, base, 3448 vreg_ofs(s, vreg), s->sew, false); 3449 3450 /* Flush out-of-range indexing to zero. */ 3451 t_vlmax = tcg_constant_i64(vlmax); 3452 t_zero = tcg_constant_i64(0); 3453 tcg_gen_extu_tl_i64(t_idx, idx); 3454 3455 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3456 t_vlmax, dest, t_zero); 3457} 3458 3459static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3460 int vreg, int idx, bool sign) 3461{ 3462 load_element(dest, tcg_env, endian_ofs(s, vreg, idx), s->sew, sign); 3463} 3464 3465/* Integer Scalar Move Instruction */ 3466 3467static void store_element(TCGv_i64 val, TCGv_ptr base, 3468 int ofs, int sew) 3469{ 3470 switch (sew) { 3471 case MO_8: 3472 tcg_gen_st8_i64(val, base, ofs); 3473 break; 3474 case MO_16: 3475 tcg_gen_st16_i64(val, base, ofs); 3476 break; 3477 case MO_32: 3478 tcg_gen_st32_i64(val, base, ofs); 3479 break; 3480 case MO_64: 3481 tcg_gen_st_i64(val, base, ofs); 3482 break; 3483 default: 3484 g_assert_not_reached(); 3485 } 3486} 3487 3488/* 3489 * Store vreg[idx] = val. 3490 * The index must be in range of VLMAX. 3491 */ 3492static void vec_element_storei(DisasContext *s, int vreg, 3493 int idx, TCGv_i64 val) 3494{ 3495 store_element(val, tcg_env, endian_ofs(s, vreg, idx), s->sew); 3496} 3497 3498/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3499static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3500{ 3501 if (require_rvv(s) && 3502 vext_check_isa_ill(s)) { 3503 TCGv_i64 t1; 3504 TCGv dest; 3505 3506 t1 = tcg_temp_new_i64(); 3507 dest = tcg_temp_new(); 3508 /* 3509 * load vreg and sign-extend to 64 bits, 3510 * then truncate to XLEN bits before storing to gpr. 3511 */ 3512 vec_element_loadi(s, t1, a->rs2, 0, true); 3513 tcg_gen_trunc_i64_tl(dest, t1); 3514 gen_set_gpr(s, a->rd, dest); 3515 tcg_gen_movi_tl(cpu_vstart, 0); 3516 finalize_rvv_inst(s); 3517 return true; 3518 } 3519 return false; 3520} 3521 3522/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3523static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3524{ 3525 if (require_rvv(s) && 3526 vext_check_isa_ill(s)) { 3527 /* This instruction ignores LMUL and vector register groups */ 3528 TCGv_i64 t1; 3529 TCGv s1; 3530 TCGLabel *over = gen_new_label(); 3531 3532 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3533 3534 t1 = tcg_temp_new_i64(); 3535 3536 /* 3537 * load gpr and sign-extend to 64 bits, 3538 * then truncate to SEW bits when storing to vreg. 3539 */ 3540 s1 = get_gpr(s, a->rs1, EXT_NONE); 3541 tcg_gen_ext_tl_i64(t1, s1); 3542 vec_element_storei(s, a->rd, 0, t1); 3543 gen_set_label(over); 3544 tcg_gen_movi_tl(cpu_vstart, 0); 3545 finalize_rvv_inst(s); 3546 return true; 3547 } 3548 return false; 3549} 3550 3551/* Floating-Point Scalar Move Instructions */ 3552static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3553{ 3554 if (require_rvv(s) && 3555 require_rvf(s) && 3556 vext_check_isa_ill(s)) { 3557 gen_set_rm(s, RISCV_FRM_DYN); 3558 3559 unsigned int ofs = (8 << s->sew); 3560 unsigned int len = 64 - ofs; 3561 TCGv_i64 t_nan; 3562 3563 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3564 /* NaN-box f[rd] as necessary for SEW */ 3565 if (len) { 3566 t_nan = tcg_constant_i64(UINT64_MAX); 3567 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3568 t_nan, ofs, len); 3569 } 3570 3571 mark_fs_dirty(s); 3572 tcg_gen_movi_tl(cpu_vstart, 0); 3573 finalize_rvv_inst(s); 3574 return true; 3575 } 3576 return false; 3577} 3578 3579/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3580static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3581{ 3582 if (require_rvv(s) && 3583 require_rvf(s) && 3584 vext_check_isa_ill(s)) { 3585 gen_set_rm(s, RISCV_FRM_DYN); 3586 3587 /* The instructions ignore LMUL and vector register group. */ 3588 TCGv_i64 t1; 3589 TCGLabel *over = gen_new_label(); 3590 3591 /* if vstart >= vl, skip vector register write back */ 3592 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3593 3594 /* NaN-box f[rs1] */ 3595 t1 = tcg_temp_new_i64(); 3596 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3597 3598 vec_element_storei(s, a->rd, 0, t1); 3599 3600 gen_set_label(over); 3601 tcg_gen_movi_tl(cpu_vstart, 0); 3602 finalize_rvv_inst(s); 3603 return true; 3604 } 3605 return false; 3606} 3607 3608/* Vector Slide Instructions */ 3609static bool slideup_check(DisasContext *s, arg_rmrr *a) 3610{ 3611 return require_rvv(s) && 3612 vext_check_isa_ill(s) && 3613 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3614} 3615 3616GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3617GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3618GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3619 3620static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3621{ 3622 return require_rvv(s) && 3623 vext_check_isa_ill(s) && 3624 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3625} 3626 3627GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3628GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3629GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3630 3631/* Vector Floating-Point Slide Instructions */ 3632static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3633{ 3634 return slideup_check(s, a) && 3635 require_rvf(s); 3636} 3637 3638static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3639{ 3640 return slidedown_check(s, a) && 3641 require_rvf(s); 3642} 3643 3644GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3645GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3646 3647/* Vector Register Gather Instruction */ 3648static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3649{ 3650 return require_rvv(s) && 3651 vext_check_isa_ill(s) && 3652 require_align(a->rd, s->lmul) && 3653 require_align(a->rs1, s->lmul) && 3654 require_align(a->rs2, s->lmul) && 3655 (a->rd != a->rs2 && a->rd != a->rs1) && 3656 require_vm(a->vm, a->rd); 3657} 3658 3659static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3660{ 3661 int8_t emul = MO_16 - s->sew + s->lmul; 3662 return require_rvv(s) && 3663 vext_check_isa_ill(s) && 3664 (emul >= -3 && emul <= 3) && 3665 require_align(a->rd, s->lmul) && 3666 require_align(a->rs1, emul) && 3667 require_align(a->rs2, s->lmul) && 3668 (a->rd != a->rs2 && a->rd != a->rs1) && 3669 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3670 a->rs1, 1 << MAX(emul, 0)) && 3671 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3672 a->rs2, 1 << MAX(s->lmul, 0)) && 3673 require_vm(a->vm, a->rd); 3674} 3675 3676GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3677GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3678 3679static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3680{ 3681 return require_rvv(s) && 3682 vext_check_isa_ill(s) && 3683 require_align(a->rd, s->lmul) && 3684 require_align(a->rs2, s->lmul) && 3685 (a->rd != a->rs2) && 3686 require_vm(a->vm, a->rd); 3687} 3688 3689/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3690static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3691{ 3692 if (!vrgather_vx_check(s, a)) { 3693 return false; 3694 } 3695 3696 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3697 int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); 3698 TCGv_i64 dest = tcg_temp_new_i64(); 3699 3700 if (a->rs1 == 0) { 3701 vec_element_loadi(s, dest, a->rs2, 0, false); 3702 } else { 3703 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3704 } 3705 3706 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3707 MAXSZ(s), MAXSZ(s), dest); 3708 finalize_rvv_inst(s); 3709 } else { 3710 static gen_helper_opivx * const fns[4] = { 3711 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3712 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3713 }; 3714 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3715 } 3716 return true; 3717} 3718 3719/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3720static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3721{ 3722 if (!vrgather_vx_check(s, a)) { 3723 return false; 3724 } 3725 3726 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3727 int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); 3728 if (a->rs1 >= vlmax) { 3729 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3730 MAXSZ(s), MAXSZ(s), 0); 3731 } else { 3732 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3733 endian_ofs(s, a->rs2, a->rs1), 3734 MAXSZ(s), MAXSZ(s)); 3735 } 3736 finalize_rvv_inst(s); 3737 } else { 3738 static gen_helper_opivx * const fns[4] = { 3739 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3740 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3741 }; 3742 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3743 s, IMM_ZX); 3744 } 3745 return true; 3746} 3747 3748/* 3749 * Vector Compress Instruction 3750 * 3751 * The destination vector register group cannot overlap the 3752 * source vector register group or the source mask register. 3753 */ 3754static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3755{ 3756 return require_rvv(s) && 3757 vext_check_isa_ill(s) && 3758 require_align(a->rd, s->lmul) && 3759 require_align(a->rs2, s->lmul) && 3760 (a->rd != a->rs2) && 3761 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3762 s->vstart_eq_zero; 3763} 3764 3765static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3766{ 3767 if (vcompress_vm_check(s, a)) { 3768 uint32_t data = 0; 3769 static gen_helper_gvec_4_ptr * const fns[4] = { 3770 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3771 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3772 }; 3773 3774 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3775 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3776 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3777 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3778 tcg_env, s->cfg_ptr->vlenb, 3779 s->cfg_ptr->vlenb, data, 3780 fns[s->sew]); 3781 finalize_rvv_inst(s); 3782 return true; 3783 } 3784 return false; 3785} 3786 3787/* 3788 * Whole Vector Register Move Instructions depend on vtype register(vsew). 3789 * Thus, we need to check vill bit. (Section 16.6) 3790 */ 3791#define GEN_VMV_WHOLE_TRANS(NAME, LEN) \ 3792static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3793{ \ 3794 if (require_rvv(s) && \ 3795 vext_check_isa_ill(s) && \ 3796 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3797 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3798 uint32_t maxsz = s->cfg_ptr->vlenb * LEN; \ 3799 if (s->vstart_eq_zero) { \ 3800 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), \ 3801 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3802 } else { \ 3803 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3804 tcg_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ 3805 } \ 3806 finalize_rvv_inst(s); \ 3807 return true; \ 3808 } \ 3809 return false; \ 3810} 3811 3812GEN_VMV_WHOLE_TRANS(vmv1r_v, 1) 3813GEN_VMV_WHOLE_TRANS(vmv2r_v, 2) 3814GEN_VMV_WHOLE_TRANS(vmv4r_v, 4) 3815GEN_VMV_WHOLE_TRANS(vmv8r_v, 8) 3816 3817static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3818{ 3819 uint8_t from = (s->sew + 3) - div; 3820 bool ret = require_rvv(s) && 3821 (from >= 3 && from <= 8) && 3822 (a->rd != a->rs2) && 3823 require_align(a->rd, s->lmul) && 3824 require_align(a->rs2, s->lmul - div) && 3825 require_vm(a->vm, a->rd) && 3826 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3827 return ret; 3828} 3829 3830static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3831{ 3832 uint32_t data = 0; 3833 gen_helper_gvec_3_ptr *fn; 3834 3835 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3836 { 3837 NULL, gen_helper_vzext_vf2_h, 3838 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3839 }, 3840 { 3841 NULL, NULL, 3842 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3843 }, 3844 { 3845 NULL, NULL, 3846 NULL, gen_helper_vzext_vf8_d 3847 }, 3848 { 3849 NULL, gen_helper_vsext_vf2_h, 3850 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3851 }, 3852 { 3853 NULL, NULL, 3854 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3855 }, 3856 { 3857 NULL, NULL, 3858 NULL, gen_helper_vsext_vf8_d 3859 } 3860 }; 3861 3862 fn = fns[seq][s->sew]; 3863 if (fn == NULL) { 3864 return false; 3865 } 3866 3867 data = FIELD_DP32(data, VDATA, VM, a->vm); 3868 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3869 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3870 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3871 3872 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3873 vreg_ofs(s, a->rs2), tcg_env, 3874 s->cfg_ptr->vlenb, 3875 s->cfg_ptr->vlenb, data, fn); 3876 3877 finalize_rvv_inst(s); 3878 return true; 3879} 3880 3881/* Vector Integer Extension */ 3882#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3883static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3884{ \ 3885 if (int_ext_check(s, a, DIV)) { \ 3886 return int_ext_op(s, a, SEQ); \ 3887 } \ 3888 return false; \ 3889} 3890 3891GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3892GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3893GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3894GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3895GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3896GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3897