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 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 774} 775 776static bool ld_us_mask_check(DisasContext *s, arg_vlm_v *a, uint8_t eew) 777{ 778 /* EMUL = 1, NFIELDS = 1 */ 779 return require_rvv(s) && vext_check_isa_ill(s); 780} 781 782static bool st_us_mask_op(DisasContext *s, arg_vsm_v *a, uint8_t eew) 783{ 784 uint32_t data = 0; 785 gen_helper_ldst_us *fn = gen_helper_vsm_v; 786 787 /* EMUL = 1, NFIELDS = 1 */ 788 data = FIELD_DP32(data, VDATA, LMUL, 0); 789 data = FIELD_DP32(data, VDATA, NF, 1); 790 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 791} 792 793static bool st_us_mask_check(DisasContext *s, arg_vsm_v *a, uint8_t eew) 794{ 795 /* EMUL = 1, NFIELDS = 1 */ 796 return require_rvv(s) && vext_check_isa_ill(s); 797} 798 799GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld_us_mask_check) 800GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check) 801 802/* 803 *** stride load and store 804 */ 805typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, 806 TCGv, TCGv_env, TCGv_i32); 807 808static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, 809 uint32_t data, gen_helper_ldst_stride *fn, 810 DisasContext *s) 811{ 812 TCGv_ptr dest, mask; 813 TCGv base, stride; 814 TCGv_i32 desc; 815 816 dest = tcg_temp_new_ptr(); 817 mask = tcg_temp_new_ptr(); 818 base = get_gpr(s, rs1, EXT_NONE); 819 stride = get_gpr(s, rs2, EXT_NONE); 820 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 821 s->cfg_ptr->vlenb, data)); 822 823 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 824 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 825 826 mark_vs_dirty(s); 827 828 fn(dest, mask, base, stride, tcg_env, desc); 829 830 finalize_rvv_inst(s); 831 return true; 832} 833 834static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 835{ 836 uint32_t data = 0; 837 gen_helper_ldst_stride *fn; 838 static gen_helper_ldst_stride * const fns[4] = { 839 gen_helper_vlse8_v, gen_helper_vlse16_v, 840 gen_helper_vlse32_v, gen_helper_vlse64_v 841 }; 842 843 fn = fns[eew]; 844 if (fn == NULL) { 845 return false; 846 } 847 848 uint8_t emul = vext_get_emul(s, eew); 849 data = FIELD_DP32(data, VDATA, VM, a->vm); 850 data = FIELD_DP32(data, VDATA, LMUL, emul); 851 data = FIELD_DP32(data, VDATA, NF, a->nf); 852 data = FIELD_DP32(data, VDATA, VTA, s->vta); 853 data = FIELD_DP32(data, VDATA, VMA, s->vma); 854 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); 855} 856 857static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 858{ 859 return require_rvv(s) && 860 vext_check_isa_ill(s) && 861 vext_check_load(s, a->rd, a->nf, a->vm, eew); 862} 863 864GEN_VEXT_TRANS(vlse8_v, MO_8, rnfvm, ld_stride_op, ld_stride_check) 865GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check) 866GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check) 867GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) 868 869static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 870{ 871 uint32_t data = 0; 872 gen_helper_ldst_stride *fn; 873 static gen_helper_ldst_stride * const fns[4] = { 874 /* masked stride store */ 875 gen_helper_vsse8_v, gen_helper_vsse16_v, 876 gen_helper_vsse32_v, gen_helper_vsse64_v 877 }; 878 879 uint8_t emul = vext_get_emul(s, eew); 880 data = FIELD_DP32(data, VDATA, VM, a->vm); 881 data = FIELD_DP32(data, VDATA, LMUL, emul); 882 data = FIELD_DP32(data, VDATA, NF, a->nf); 883 fn = fns[eew]; 884 if (fn == NULL) { 885 return false; 886 } 887 888 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); 889} 890 891static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 892{ 893 return require_rvv(s) && 894 vext_check_isa_ill(s) && 895 vext_check_store(s, a->rd, a->nf, eew); 896} 897 898GEN_VEXT_TRANS(vsse8_v, MO_8, rnfvm, st_stride_op, st_stride_check) 899GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check) 900GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check) 901GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check) 902 903/* 904 *** index load and store 905 */ 906typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, 907 TCGv_ptr, TCGv_env, TCGv_i32); 908 909static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 910 uint32_t data, gen_helper_ldst_index *fn, 911 DisasContext *s) 912{ 913 TCGv_ptr dest, mask, index; 914 TCGv base; 915 TCGv_i32 desc; 916 917 dest = tcg_temp_new_ptr(); 918 mask = tcg_temp_new_ptr(); 919 index = tcg_temp_new_ptr(); 920 base = get_gpr(s, rs1, EXT_NONE); 921 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 922 s->cfg_ptr->vlenb, data)); 923 924 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 925 tcg_gen_addi_ptr(index, tcg_env, vreg_ofs(s, vs2)); 926 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 927 928 mark_vs_dirty(s); 929 930 fn(dest, mask, base, index, tcg_env, desc); 931 932 finalize_rvv_inst(s); 933 return true; 934} 935 936static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 937{ 938 uint32_t data = 0; 939 gen_helper_ldst_index *fn; 940 static gen_helper_ldst_index * const fns[4][4] = { 941 /* 942 * offset vector register group EEW = 8, 943 * data vector register group EEW = SEW 944 */ 945 { gen_helper_vlxei8_8_v, gen_helper_vlxei8_16_v, 946 gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v }, 947 /* 948 * offset vector register group EEW = 16, 949 * data vector register group EEW = SEW 950 */ 951 { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v, 952 gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v }, 953 /* 954 * offset vector register group EEW = 32, 955 * data vector register group EEW = SEW 956 */ 957 { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v, 958 gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v }, 959 /* 960 * offset vector register group EEW = 64, 961 * data vector register group EEW = SEW 962 */ 963 { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v, 964 gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v } 965 }; 966 967 fn = fns[eew][s->sew]; 968 969 uint8_t emul = vext_get_emul(s, s->sew); 970 data = FIELD_DP32(data, VDATA, VM, a->vm); 971 data = FIELD_DP32(data, VDATA, LMUL, emul); 972 data = FIELD_DP32(data, VDATA, NF, a->nf); 973 data = FIELD_DP32(data, VDATA, VTA, s->vta); 974 data = FIELD_DP32(data, VDATA, VMA, s->vma); 975 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); 976} 977 978static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 979{ 980 return require_rvv(s) && 981 vext_check_isa_ill(s) && 982 vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); 983} 984 985GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) 986GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check) 987GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check) 988GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check) 989 990static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 991{ 992 uint32_t data = 0; 993 gen_helper_ldst_index *fn; 994 static gen_helper_ldst_index * const fns[4][4] = { 995 /* 996 * offset vector register group EEW = 8, 997 * data vector register group EEW = SEW 998 */ 999 { gen_helper_vsxei8_8_v, gen_helper_vsxei8_16_v, 1000 gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v }, 1001 /* 1002 * offset vector register group EEW = 16, 1003 * data vector register group EEW = SEW 1004 */ 1005 { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v, 1006 gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v }, 1007 /* 1008 * offset vector register group EEW = 32, 1009 * data vector register group EEW = SEW 1010 */ 1011 { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v, 1012 gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v }, 1013 /* 1014 * offset vector register group EEW = 64, 1015 * data vector register group EEW = SEW 1016 */ 1017 { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v, 1018 gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v } 1019 }; 1020 1021 fn = fns[eew][s->sew]; 1022 1023 uint8_t emul = vext_get_emul(s, s->sew); 1024 data = FIELD_DP32(data, VDATA, VM, a->vm); 1025 data = FIELD_DP32(data, VDATA, LMUL, emul); 1026 data = FIELD_DP32(data, VDATA, NF, a->nf); 1027 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s); 1028} 1029 1030static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 1031{ 1032 return require_rvv(s) && 1033 vext_check_isa_ill(s) && 1034 vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); 1035} 1036 1037GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) 1038GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check) 1039GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check) 1040GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check) 1041 1042/* 1043 *** unit stride fault-only-first load 1044 */ 1045static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, 1046 gen_helper_ldst_us *fn, DisasContext *s) 1047{ 1048 TCGv_ptr dest, mask; 1049 TCGv base; 1050 TCGv_i32 desc; 1051 1052 dest = tcg_temp_new_ptr(); 1053 mask = tcg_temp_new_ptr(); 1054 base = get_gpr(s, rs1, EXT_NONE); 1055 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1056 s->cfg_ptr->vlenb, data)); 1057 1058 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1059 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1060 1061 fn(dest, mask, base, tcg_env, desc); 1062 1063 finalize_rvv_inst(s); 1064 return true; 1065} 1066 1067static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 1068{ 1069 uint32_t data = 0; 1070 gen_helper_ldst_us *fn; 1071 static gen_helper_ldst_us * const fns[4] = { 1072 gen_helper_vle8ff_v, gen_helper_vle16ff_v, 1073 gen_helper_vle32ff_v, gen_helper_vle64ff_v 1074 }; 1075 1076 fn = fns[eew]; 1077 if (fn == NULL) { 1078 return false; 1079 } 1080 1081 uint8_t emul = vext_get_emul(s, eew); 1082 data = FIELD_DP32(data, VDATA, VM, a->vm); 1083 data = FIELD_DP32(data, VDATA, LMUL, emul); 1084 data = FIELD_DP32(data, VDATA, NF, a->nf); 1085 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1086 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1087 return ldff_trans(a->rd, a->rs1, data, fn, s); 1088} 1089 1090GEN_VEXT_TRANS(vle8ff_v, MO_8, r2nfvm, ldff_op, ld_us_check) 1091GEN_VEXT_TRANS(vle16ff_v, MO_16, r2nfvm, ldff_op, ld_us_check) 1092GEN_VEXT_TRANS(vle32ff_v, MO_32, r2nfvm, ldff_op, ld_us_check) 1093GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) 1094 1095/* 1096 * load and store whole register instructions 1097 */ 1098typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); 1099 1100static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, 1101 gen_helper_ldst_whole *fn, 1102 DisasContext *s) 1103{ 1104 TCGv_ptr dest; 1105 TCGv base; 1106 TCGv_i32 desc; 1107 1108 uint32_t data = FIELD_DP32(0, VDATA, NF, nf); 1109 dest = tcg_temp_new_ptr(); 1110 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1111 s->cfg_ptr->vlenb, data)); 1112 1113 base = get_gpr(s, rs1, EXT_NONE); 1114 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1115 1116 mark_vs_dirty(s); 1117 1118 fn(dest, base, tcg_env, desc); 1119 1120 finalize_rvv_inst(s); 1121 return true; 1122} 1123 1124/* 1125 * load and store whole register instructions ignore vtype and vl setting. 1126 * Thus, we don't need to check vill bit. (Section 7.9) 1127 */ 1128#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF) \ 1129static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 1130{ \ 1131 if (require_rvv(s) && \ 1132 QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ 1133 return ldst_whole_trans(a->rd, a->rs1, ARG_NF, \ 1134 gen_helper_##NAME, s); \ 1135 } \ 1136 return false; \ 1137} 1138 1139GEN_LDST_WHOLE_TRANS(vl1re8_v, 1) 1140GEN_LDST_WHOLE_TRANS(vl1re16_v, 1) 1141GEN_LDST_WHOLE_TRANS(vl1re32_v, 1) 1142GEN_LDST_WHOLE_TRANS(vl1re64_v, 1) 1143GEN_LDST_WHOLE_TRANS(vl2re8_v, 2) 1144GEN_LDST_WHOLE_TRANS(vl2re16_v, 2) 1145GEN_LDST_WHOLE_TRANS(vl2re32_v, 2) 1146GEN_LDST_WHOLE_TRANS(vl2re64_v, 2) 1147GEN_LDST_WHOLE_TRANS(vl4re8_v, 4) 1148GEN_LDST_WHOLE_TRANS(vl4re16_v, 4) 1149GEN_LDST_WHOLE_TRANS(vl4re32_v, 4) 1150GEN_LDST_WHOLE_TRANS(vl4re64_v, 4) 1151GEN_LDST_WHOLE_TRANS(vl8re8_v, 8) 1152GEN_LDST_WHOLE_TRANS(vl8re16_v, 8) 1153GEN_LDST_WHOLE_TRANS(vl8re32_v, 8) 1154GEN_LDST_WHOLE_TRANS(vl8re64_v, 8) 1155 1156/* 1157 * The vector whole register store instructions are encoded similar to 1158 * unmasked unit-stride store of elements with EEW=8. 1159 */ 1160GEN_LDST_WHOLE_TRANS(vs1r_v, 1) 1161GEN_LDST_WHOLE_TRANS(vs2r_v, 2) 1162GEN_LDST_WHOLE_TRANS(vs4r_v, 4) 1163GEN_LDST_WHOLE_TRANS(vs8r_v, 8) 1164 1165/* 1166 *** Vector Integer Arithmetic Instructions 1167 */ 1168 1169/* 1170 * MAXSZ returns the maximum vector size can be operated in bytes, 1171 * which is used in GVEC IR when vl_eq_vlmax flag is set to true 1172 * to accelerate vector operation. 1173 */ 1174static inline uint32_t MAXSZ(DisasContext *s) 1175{ 1176 int max_sz = s->cfg_ptr->vlenb * 8; 1177 return max_sz >> (3 - s->lmul); 1178} 1179 1180static bool opivv_check(DisasContext *s, arg_rmrr *a) 1181{ 1182 return require_rvv(s) && 1183 vext_check_isa_ill(s) && 1184 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1185} 1186 1187typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 1188 uint32_t, uint32_t, uint32_t); 1189 1190static inline bool 1191do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 1192 gen_helper_gvec_4_ptr *fn) 1193{ 1194 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1195 gvec_fn(s->sew, vreg_ofs(s, a->rd), 1196 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 1197 MAXSZ(s), MAXSZ(s)); 1198 } else { 1199 uint32_t data = 0; 1200 1201 data = FIELD_DP32(data, VDATA, VM, a->vm); 1202 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1203 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1204 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1205 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1206 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 1207 tcg_env, s->cfg_ptr->vlenb, 1208 s->cfg_ptr->vlenb, data, fn); 1209 } 1210 finalize_rvv_inst(s); 1211 return true; 1212} 1213 1214/* OPIVV with GVEC IR */ 1215#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 1216static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1217{ \ 1218 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1219 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1220 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1221 }; \ 1222 if (!opivv_check(s, a)) { \ 1223 return false; \ 1224 } \ 1225 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1226} 1227 1228GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 1229GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 1230 1231typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 1232 TCGv_env, TCGv_i32); 1233 1234static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 1235 gen_helper_opivx *fn, DisasContext *s) 1236{ 1237 TCGv_ptr dest, src2, mask; 1238 TCGv src1; 1239 TCGv_i32 desc; 1240 uint32_t data = 0; 1241 1242 dest = tcg_temp_new_ptr(); 1243 mask = tcg_temp_new_ptr(); 1244 src2 = tcg_temp_new_ptr(); 1245 src1 = get_gpr(s, rs1, EXT_SIGN); 1246 1247 data = FIELD_DP32(data, VDATA, VM, vm); 1248 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1249 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1250 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1251 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1252 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1253 s->cfg_ptr->vlenb, data)); 1254 1255 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1256 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 1257 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1258 1259 fn(dest, mask, src1, src2, tcg_env, desc); 1260 1261 finalize_rvv_inst(s); 1262 return true; 1263} 1264 1265static bool opivx_check(DisasContext *s, arg_rmrr *a) 1266{ 1267 return require_rvv(s) && 1268 vext_check_isa_ill(s) && 1269 vext_check_ss(s, a->rd, a->rs2, a->vm); 1270} 1271 1272typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 1273 uint32_t, uint32_t); 1274 1275static inline bool 1276do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 1277 gen_helper_opivx *fn) 1278{ 1279 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1280 TCGv_i64 src1 = tcg_temp_new_i64(); 1281 1282 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 1283 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1284 src1, MAXSZ(s), MAXSZ(s)); 1285 1286 finalize_rvv_inst(s); 1287 return true; 1288 } 1289 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1290} 1291 1292/* OPIVX with GVEC IR */ 1293#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 1294static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1295{ \ 1296 static gen_helper_opivx * const fns[4] = { \ 1297 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1298 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1299 }; \ 1300 if (!opivx_check(s, a)) { \ 1301 return false; \ 1302 } \ 1303 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1304} 1305 1306GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 1307GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 1308 1309static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1310{ 1311 tcg_gen_vec_sub8_i64(d, b, a); 1312} 1313 1314static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1315{ 1316 tcg_gen_vec_sub16_i64(d, b, a); 1317} 1318 1319static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 1320{ 1321 tcg_gen_sub_i32(ret, arg2, arg1); 1322} 1323 1324static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1325{ 1326 tcg_gen_sub_i64(ret, arg2, arg1); 1327} 1328 1329static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 1330{ 1331 tcg_gen_sub_vec(vece, r, b, a); 1332} 1333 1334static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 1335 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 1336{ 1337 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 1338 static const GVecGen2s rsub_op[4] = { 1339 { .fni8 = gen_vec_rsub8_i64, 1340 .fniv = gen_rsub_vec, 1341 .fno = gen_helper_vec_rsubs8, 1342 .opt_opc = vecop_list, 1343 .vece = MO_8 }, 1344 { .fni8 = gen_vec_rsub16_i64, 1345 .fniv = gen_rsub_vec, 1346 .fno = gen_helper_vec_rsubs16, 1347 .opt_opc = vecop_list, 1348 .vece = MO_16 }, 1349 { .fni4 = gen_rsub_i32, 1350 .fniv = gen_rsub_vec, 1351 .fno = gen_helper_vec_rsubs32, 1352 .opt_opc = vecop_list, 1353 .vece = MO_32 }, 1354 { .fni8 = gen_rsub_i64, 1355 .fniv = gen_rsub_vec, 1356 .fno = gen_helper_vec_rsubs64, 1357 .opt_opc = vecop_list, 1358 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 1359 .vece = MO_64 }, 1360 }; 1361 1362 tcg_debug_assert(vece <= MO_64); 1363 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 1364} 1365 1366GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 1367 1368typedef enum { 1369 IMM_ZX, /* Zero-extended */ 1370 IMM_SX, /* Sign-extended */ 1371 IMM_TRUNC_SEW, /* Truncate to log(SEW) bits */ 1372 IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */ 1373} imm_mode_t; 1374 1375static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode) 1376{ 1377 switch (imm_mode) { 1378 case IMM_ZX: 1379 return extract64(imm, 0, 5); 1380 case IMM_SX: 1381 return sextract64(imm, 0, 5); 1382 case IMM_TRUNC_SEW: 1383 return extract64(imm, 0, s->sew + 3); 1384 case IMM_TRUNC_2SEW: 1385 return extract64(imm, 0, s->sew + 4); 1386 default: 1387 g_assert_not_reached(); 1388 } 1389} 1390 1391static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 1392 gen_helper_opivx *fn, DisasContext *s, 1393 imm_mode_t imm_mode) 1394{ 1395 TCGv_ptr dest, src2, mask; 1396 TCGv src1; 1397 TCGv_i32 desc; 1398 uint32_t data = 0; 1399 1400 dest = tcg_temp_new_ptr(); 1401 mask = tcg_temp_new_ptr(); 1402 src2 = tcg_temp_new_ptr(); 1403 src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode)); 1404 1405 data = FIELD_DP32(data, VDATA, VM, vm); 1406 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1407 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1408 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1409 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1410 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 1411 s->cfg_ptr->vlenb, data)); 1412 1413 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 1414 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 1415 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 1416 1417 fn(dest, mask, src1, src2, tcg_env, desc); 1418 1419 finalize_rvv_inst(s); 1420 return true; 1421} 1422 1423typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1424 uint32_t, uint32_t); 1425 1426static inline bool 1427do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1428 gen_helper_opivx *fn, imm_mode_t imm_mode) 1429{ 1430 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1431 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1432 extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); 1433 finalize_rvv_inst(s); 1434 return true; 1435 } 1436 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode); 1437} 1438 1439/* OPIVI with GVEC IR */ 1440#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \ 1441static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1442{ \ 1443 static gen_helper_opivx * const fns[4] = { \ 1444 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1445 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1446 }; \ 1447 if (!opivx_check(s, a)) { \ 1448 return false; \ 1449 } \ 1450 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1451 fns[s->sew], IMM_MODE); \ 1452} 1453 1454GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi) 1455 1456static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1457 int64_t c, uint32_t oprsz, uint32_t maxsz) 1458{ 1459 TCGv_i64 tmp = tcg_constant_i64(c); 1460 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1461} 1462 1463GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi) 1464 1465/* Vector Widening Integer Add/Subtract */ 1466 1467/* OPIVV with WIDEN */ 1468static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1469{ 1470 return require_rvv(s) && 1471 vext_check_isa_ill(s) && 1472 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 1473} 1474 1475static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1476 gen_helper_gvec_4_ptr *fn, 1477 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1478{ 1479 if (checkfn(s, a)) { 1480 uint32_t data = 0; 1481 1482 data = FIELD_DP32(data, VDATA, VM, a->vm); 1483 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1484 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1485 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1486 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1487 vreg_ofs(s, a->rs1), 1488 vreg_ofs(s, a->rs2), 1489 tcg_env, s->cfg_ptr->vlenb, 1490 s->cfg_ptr->vlenb, 1491 data, fn); 1492 finalize_rvv_inst(s); 1493 return true; 1494 } 1495 return false; 1496} 1497 1498#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1499static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1500{ \ 1501 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1502 gen_helper_##NAME##_b, \ 1503 gen_helper_##NAME##_h, \ 1504 gen_helper_##NAME##_w \ 1505 }; \ 1506 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1507} 1508 1509GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1510GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1511GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1512GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1513 1514/* OPIVX with WIDEN */ 1515static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1516{ 1517 return require_rvv(s) && 1518 vext_check_isa_ill(s) && 1519 vext_check_ds(s, a->rd, a->rs2, a->vm); 1520} 1521 1522#define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \ 1523static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1524{ \ 1525 if (CHECK(s, a)) { \ 1526 static gen_helper_opivx * const fns[3] = { \ 1527 gen_helper_##NAME##_b, \ 1528 gen_helper_##NAME##_h, \ 1529 gen_helper_##NAME##_w \ 1530 }; \ 1531 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); \ 1532 } \ 1533 return false; \ 1534} 1535 1536GEN_OPIVX_WIDEN_TRANS(vwaddu_vx, opivx_widen_check) 1537GEN_OPIVX_WIDEN_TRANS(vwadd_vx, opivx_widen_check) 1538GEN_OPIVX_WIDEN_TRANS(vwsubu_vx, opivx_widen_check) 1539GEN_OPIVX_WIDEN_TRANS(vwsub_vx, opivx_widen_check) 1540 1541/* WIDEN OPIVV with WIDEN */ 1542static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1543{ 1544 return require_rvv(s) && 1545 vext_check_isa_ill(s) && 1546 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 1547} 1548 1549static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1550 gen_helper_gvec_4_ptr *fn) 1551{ 1552 if (opiwv_widen_check(s, a)) { 1553 uint32_t data = 0; 1554 1555 data = FIELD_DP32(data, VDATA, VM, a->vm); 1556 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1557 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1558 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1559 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1560 vreg_ofs(s, a->rs1), 1561 vreg_ofs(s, a->rs2), 1562 tcg_env, s->cfg_ptr->vlenb, 1563 s->cfg_ptr->vlenb, data, fn); 1564 finalize_rvv_inst(s); 1565 return true; 1566 } 1567 return false; 1568} 1569 1570#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1571static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1572{ \ 1573 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1574 gen_helper_##NAME##_b, \ 1575 gen_helper_##NAME##_h, \ 1576 gen_helper_##NAME##_w \ 1577 }; \ 1578 return do_opiwv_widen(s, a, fns[s->sew]); \ 1579} 1580 1581GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1582GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1583GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1584GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1585 1586/* WIDEN OPIVX with WIDEN */ 1587static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1588{ 1589 return require_rvv(s) && 1590 vext_check_isa_ill(s) && 1591 vext_check_dd(s, a->rd, a->rs2, a->vm); 1592} 1593 1594static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1595 gen_helper_opivx *fn) 1596{ 1597 if (opiwx_widen_check(s, a)) { 1598 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1599 } 1600 return false; 1601} 1602 1603#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1604static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1605{ \ 1606 static gen_helper_opivx * const fns[3] = { \ 1607 gen_helper_##NAME##_b, \ 1608 gen_helper_##NAME##_h, \ 1609 gen_helper_##NAME##_w \ 1610 }; \ 1611 return do_opiwx_widen(s, a, fns[s->sew]); \ 1612} 1613 1614GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1615GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1616GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1617GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1618 1619static bool opivv_trans(uint32_t vd, uint32_t vs1, uint32_t vs2, uint32_t vm, 1620 gen_helper_gvec_4_ptr *fn, DisasContext *s) 1621{ 1622 uint32_t data = 0; 1623 1624 data = FIELD_DP32(data, VDATA, VM, vm); 1625 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1626 data = FIELD_DP32(data, VDATA, VTA, s->vta); 1627 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s); 1628 data = FIELD_DP32(data, VDATA, VMA, s->vma); 1629 tcg_gen_gvec_4_ptr(vreg_ofs(s, vd), vreg_ofs(s, 0), vreg_ofs(s, vs1), 1630 vreg_ofs(s, vs2), tcg_env, s->cfg_ptr->vlenb, 1631 s->cfg_ptr->vlenb, data, fn); 1632 finalize_rvv_inst(s); 1633 return true; 1634} 1635 1636/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1637/* OPIVV without GVEC IR */ 1638#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1639static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1640{ \ 1641 if (CHECK(s, a)) { \ 1642 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1643 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1644 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1645 }; \ 1646 return opivv_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1647 } \ 1648 return false; \ 1649} 1650 1651/* 1652 * For vadc and vsbc, an illegal instruction exception is raised if the 1653 * destination vector register is v0 and LMUL > 1. (Section 11.4) 1654 */ 1655static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1656{ 1657 return require_rvv(s) && 1658 vext_check_isa_ill(s) && 1659 (a->rd != 0) && 1660 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1661} 1662 1663GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1664GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1665 1666/* 1667 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1668 * destination vector register overlaps a source vector register group. 1669 */ 1670static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1671{ 1672 return require_rvv(s) && 1673 vext_check_isa_ill(s) && 1674 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1675} 1676 1677GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1678GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1679 1680static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1681{ 1682 return require_rvv(s) && 1683 vext_check_isa_ill(s) && 1684 (a->rd != 0) && 1685 vext_check_ss(s, a->rd, a->rs2, a->vm); 1686} 1687 1688/* OPIVX without GVEC IR */ 1689#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1690static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1691{ \ 1692 if (CHECK(s, a)) { \ 1693 static gen_helper_opivx * const fns[4] = { \ 1694 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1695 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1696 }; \ 1697 \ 1698 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1699 } \ 1700 return false; \ 1701} 1702 1703GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1704GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1705 1706static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1707{ 1708 return require_rvv(s) && 1709 vext_check_isa_ill(s) && 1710 vext_check_ms(s, a->rd, a->rs2); 1711} 1712 1713GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1714GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1715 1716/* OPIVI without GVEC IR */ 1717#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK) \ 1718static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1719{ \ 1720 if (CHECK(s, a)) { \ 1721 static gen_helper_opivx * const fns[4] = { \ 1722 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1723 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1724 }; \ 1725 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1726 fns[s->sew], s, IMM_MODE); \ 1727 } \ 1728 return false; \ 1729} 1730 1731GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check) 1732GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check) 1733 1734/* Vector Bitwise Logical Instructions */ 1735GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1736GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1737GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1738GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1739GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1740GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1741GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi) 1742GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx, ori) 1743GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori) 1744 1745/* Vector Single-Width Bit Shift Instructions */ 1746GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1747GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1748GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1749 1750typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1751 uint32_t, uint32_t); 1752 1753static inline bool 1754do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1755 gen_helper_opivx *fn) 1756{ 1757 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 1758 TCGv_i32 src1 = tcg_temp_new_i32(); 1759 1760 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1761 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1762 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1763 src1, MAXSZ(s), MAXSZ(s)); 1764 1765 finalize_rvv_inst(s); 1766 return true; 1767 } 1768 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1769} 1770 1771#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1772static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1773{ \ 1774 static gen_helper_opivx * const fns[4] = { \ 1775 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1776 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1777 }; \ 1778 if (!opivx_check(s, a)) { \ 1779 return false; \ 1780 } \ 1781 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1782} 1783 1784GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1785GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1786GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1787 1788GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_TRUNC_SEW, vsll_vx, shli) 1789GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_TRUNC_SEW, vsrl_vx, shri) 1790GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_TRUNC_SEW, vsra_vx, sari) 1791 1792/* Vector Narrowing Integer Right Shift Instructions */ 1793static bool opiwv_narrow_check(DisasContext *s, arg_rmrr *a) 1794{ 1795 return require_rvv(s) && 1796 vext_check_isa_ill(s) && 1797 vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm); 1798} 1799 1800/* OPIVV with NARROW */ 1801#define GEN_OPIWV_NARROW_TRANS(NAME) \ 1802static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1803{ \ 1804 if (opiwv_narrow_check(s, a)) { \ 1805 uint32_t data = 0; \ 1806 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1807 gen_helper_##NAME##_b, \ 1808 gen_helper_##NAME##_h, \ 1809 gen_helper_##NAME##_w, \ 1810 }; \ 1811 \ 1812 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1813 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1814 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 1815 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 1816 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1817 vreg_ofs(s, a->rs1), \ 1818 vreg_ofs(s, a->rs2), tcg_env, \ 1819 s->cfg_ptr->vlenb, \ 1820 s->cfg_ptr->vlenb, data, \ 1821 fns[s->sew]); \ 1822 finalize_rvv_inst(s); \ 1823 return true; \ 1824 } \ 1825 return false; \ 1826} 1827GEN_OPIWV_NARROW_TRANS(vnsra_wv) 1828GEN_OPIWV_NARROW_TRANS(vnsrl_wv) 1829 1830static bool opiwx_narrow_check(DisasContext *s, arg_rmrr *a) 1831{ 1832 return require_rvv(s) && 1833 vext_check_isa_ill(s) && 1834 vext_check_sd(s, a->rd, a->rs2, a->vm); 1835} 1836 1837/* OPIVX with NARROW */ 1838#define GEN_OPIWX_NARROW_TRANS(NAME) \ 1839static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1840{ \ 1841 if (opiwx_narrow_check(s, a)) { \ 1842 static gen_helper_opivx * const fns[3] = { \ 1843 gen_helper_##NAME##_b, \ 1844 gen_helper_##NAME##_h, \ 1845 gen_helper_##NAME##_w, \ 1846 }; \ 1847 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1848 } \ 1849 return false; \ 1850} 1851 1852GEN_OPIWX_NARROW_TRANS(vnsra_wx) 1853GEN_OPIWX_NARROW_TRANS(vnsrl_wx) 1854 1855/* OPIWI with NARROW */ 1856#define GEN_OPIWI_NARROW_TRANS(NAME, IMM_MODE, OPIVX) \ 1857static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1858{ \ 1859 if (opiwx_narrow_check(s, a)) { \ 1860 static gen_helper_opivx * const fns[3] = { \ 1861 gen_helper_##OPIVX##_b, \ 1862 gen_helper_##OPIVX##_h, \ 1863 gen_helper_##OPIVX##_w, \ 1864 }; \ 1865 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1866 fns[s->sew], s, IMM_MODE); \ 1867 } \ 1868 return false; \ 1869} 1870 1871GEN_OPIWI_NARROW_TRANS(vnsra_wi, IMM_ZX, vnsra_wx) 1872GEN_OPIWI_NARROW_TRANS(vnsrl_wi, IMM_ZX, vnsrl_wx) 1873 1874/* Vector Integer Comparison Instructions */ 1875/* 1876 * For all comparison instructions, an illegal instruction exception is raised 1877 * if the destination vector register overlaps a source vector register group 1878 * and LMUL > 1. 1879 */ 1880static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1881{ 1882 return require_rvv(s) && 1883 vext_check_isa_ill(s) && 1884 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1885} 1886 1887GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1888GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1889GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1890GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1891GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1892GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1893 1894static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1895{ 1896 return require_rvv(s) && 1897 vext_check_isa_ill(s) && 1898 vext_check_ms(s, a->rd, a->rs2); 1899} 1900 1901GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1902GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1903GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1904GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1905GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1906GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1907GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1908GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1909 1910GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check) 1911GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check) 1912GEN_OPIVI_TRANS(vmsleu_vi, IMM_SX, vmsleu_vx, opivx_cmp_check) 1913GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check) 1914GEN_OPIVI_TRANS(vmsgtu_vi, IMM_SX, vmsgtu_vx, opivx_cmp_check) 1915GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check) 1916 1917/* Vector Integer Min/Max Instructions */ 1918GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1919GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1920GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1921GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1922GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1923GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1924GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1925GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1926 1927/* Vector Single-Width Integer Multiply Instructions */ 1928 1929static bool vmulh_vv_check(DisasContext *s, arg_rmrr *a) 1930{ 1931 /* 1932 * All Zve* extensions support all vector integer instructions, 1933 * except that the vmulh integer multiply variants 1934 * that return the high word of the product 1935 * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) 1936 * are not included for EEW=64 in Zve64*. (Section 18.2) 1937 */ 1938 return opivv_check(s, a) && 1939 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 1940} 1941 1942static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a) 1943{ 1944 /* 1945 * All Zve* extensions support all vector integer instructions, 1946 * except that the vmulh integer multiply variants 1947 * that return the high word of the product 1948 * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) 1949 * are not included for EEW=64 in Zve64*. (Section 18.2) 1950 */ 1951 return opivx_check(s, a) && 1952 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 1953} 1954 1955GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1956GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check) 1957GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check) 1958GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check) 1959GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1960GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check) 1961GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check) 1962GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check) 1963 1964/* Vector Integer Divide Instructions */ 1965GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1966GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1967GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1968GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1969GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1970GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1971GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1972GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1973 1974/* Vector Widening Integer Multiply Instructions */ 1975GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1976GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1977GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1978GEN_OPIVX_WIDEN_TRANS(vwmul_vx, opivx_widen_check) 1979GEN_OPIVX_WIDEN_TRANS(vwmulu_vx, opivx_widen_check) 1980GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx, opivx_widen_check) 1981 1982/* Vector Single-Width Integer Multiply-Add Instructions */ 1983GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1984GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1985GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1986GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1987GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1988GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1989GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1990GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1991 1992/* Vector Widening Integer Multiply-Add Instructions */ 1993GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1994GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1995GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1996GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check) 1997GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check) 1998GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check) 1999GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check) 2000 2001/* Vector Integer Merge and Move Instructions */ 2002static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 2003{ 2004 if (require_rvv(s) && 2005 vext_check_isa_ill(s) && 2006 /* vmv.v.v has rs2 = 0 and vm = 1 */ 2007 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 2008 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2009 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 2010 vreg_ofs(s, a->rs1), 2011 MAXSZ(s), MAXSZ(s)); 2012 } else { 2013 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2014 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2015 static gen_helper_gvec_2_ptr * const fns[4] = { 2016 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 2017 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 2018 }; 2019 2020 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 2021 tcg_env, s->cfg_ptr->vlenb, 2022 s->cfg_ptr->vlenb, data, 2023 fns[s->sew]); 2024 } 2025 finalize_rvv_inst(s); 2026 return true; 2027 } 2028 return false; 2029} 2030 2031typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 2032static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 2033{ 2034 if (require_rvv(s) && 2035 vext_check_isa_ill(s) && 2036 /* vmv.v.x has rs2 = 0 and vm = 1 */ 2037 vext_check_ss(s, a->rd, 0, 1)) { 2038 TCGv s1; 2039 2040 s1 = get_gpr(s, a->rs1, EXT_SIGN); 2041 2042 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2043 if (get_xl(s) == MXL_RV32 && s->sew == MO_64) { 2044 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2045 tcg_gen_ext_tl_i64(s1_i64, s1); 2046 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2047 MAXSZ(s), MAXSZ(s), s1_i64); 2048 } else { 2049 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 2050 MAXSZ(s), MAXSZ(s), s1); 2051 } 2052 } else { 2053 TCGv_i32 desc; 2054 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2055 TCGv_ptr dest = tcg_temp_new_ptr(); 2056 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2057 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2058 static gen_helper_vmv_vx * const fns[4] = { 2059 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2060 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2061 }; 2062 2063 tcg_gen_ext_tl_i64(s1_i64, s1); 2064 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2065 s->cfg_ptr->vlenb, data)); 2066 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2067 fns[s->sew](dest, s1_i64, tcg_env, desc); 2068 } 2069 2070 finalize_rvv_inst(s); 2071 return true; 2072 } 2073 return false; 2074} 2075 2076static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 2077{ 2078 if (require_rvv(s) && 2079 vext_check_isa_ill(s) && 2080 /* vmv.v.i has rs2 = 0 and vm = 1 */ 2081 vext_check_ss(s, a->rd, 0, 1)) { 2082 int64_t simm = sextract64(a->rs1, 0, 5); 2083 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2084 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 2085 MAXSZ(s), MAXSZ(s), simm); 2086 } else { 2087 TCGv_i32 desc; 2088 TCGv_i64 s1; 2089 TCGv_ptr dest; 2090 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2091 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2092 static gen_helper_vmv_vx * const fns[4] = { 2093 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2094 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2095 }; 2096 2097 s1 = tcg_constant_i64(simm); 2098 dest = tcg_temp_new_ptr(); 2099 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2100 s->cfg_ptr->vlenb, data)); 2101 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2102 fns[s->sew](dest, s1, tcg_env, desc); 2103 } 2104 finalize_rvv_inst(s); 2105 return true; 2106 } 2107 return false; 2108} 2109 2110GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 2111GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 2112GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 2113 2114/* 2115 *** Vector Fixed-Point Arithmetic Instructions 2116 */ 2117 2118/* Vector Single-Width Saturating Add and Subtract */ 2119GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 2120GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 2121GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 2122GEN_OPIVV_TRANS(vssub_vv, opivv_check) 2123GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 2124GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 2125GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 2126GEN_OPIVX_TRANS(vssub_vx, opivx_check) 2127GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check) 2128GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 2129 2130/* Vector Single-Width Averaging Add and Subtract */ 2131GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 2132GEN_OPIVV_TRANS(vaaddu_vv, opivv_check) 2133GEN_OPIVV_TRANS(vasub_vv, opivv_check) 2134GEN_OPIVV_TRANS(vasubu_vv, opivv_check) 2135GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 2136GEN_OPIVX_TRANS(vaaddu_vx, opivx_check) 2137GEN_OPIVX_TRANS(vasub_vx, opivx_check) 2138GEN_OPIVX_TRANS(vasubu_vx, opivx_check) 2139 2140/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 2141 2142static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a) 2143{ 2144 /* 2145 * All Zve* extensions support all vector fixed-point arithmetic 2146 * instructions, except that vsmul.vv and vsmul.vx are not supported 2147 * for EEW=64 in Zve64*. (Section 18.2) 2148 */ 2149 return opivv_check(s, a) && 2150 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2151} 2152 2153static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a) 2154{ 2155 /* 2156 * All Zve* extensions support all vector fixed-point arithmetic 2157 * instructions, except that vsmul.vv and vsmul.vx are not supported 2158 * for EEW=64 in Zve64*. (Section 18.2) 2159 */ 2160 return opivx_check(s, a) && 2161 (!has_ext(s, RVV) ? s->sew != MO_64 : true); 2162} 2163 2164GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check) 2165GEN_OPIVX_TRANS(vsmul_vx, vsmul_vx_check) 2166 2167/* Vector Single-Width Scaling Shift Instructions */ 2168GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 2169GEN_OPIVV_TRANS(vssra_vv, opivv_check) 2170GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 2171GEN_OPIVX_TRANS(vssra_vx, opivx_check) 2172GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check) 2173GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check) 2174 2175/* Vector Narrowing Fixed-Point Clip Instructions */ 2176GEN_OPIWV_NARROW_TRANS(vnclipu_wv) 2177GEN_OPIWV_NARROW_TRANS(vnclip_wv) 2178GEN_OPIWX_NARROW_TRANS(vnclipu_wx) 2179GEN_OPIWX_NARROW_TRANS(vnclip_wx) 2180GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx) 2181GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx) 2182 2183/* 2184 *** Vector Float Point Arithmetic Instructions 2185 */ 2186 2187/* 2188 * As RVF-only cpus always have values NaN-boxed to 64-bits, 2189 * RVF and RVD can be treated equally. 2190 * We don't have to deal with the cases of: SEW > FLEN. 2191 * 2192 * If SEW < FLEN, check whether input fp register is a valid 2193 * NaN-boxed value, in which case the least-significant SEW bits 2194 * of the f register are used, else the canonical NaN value is used. 2195 */ 2196static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 2197{ 2198 switch (s->sew) { 2199 case 1: 2200 gen_check_nanbox_h(out, in); 2201 break; 2202 case 2: 2203 gen_check_nanbox_s(out, in); 2204 break; 2205 case 3: 2206 tcg_gen_mov_i64(out, in); 2207 break; 2208 default: 2209 g_assert_not_reached(); 2210 } 2211} 2212 2213/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 2214 2215/* 2216 * If the current SEW does not correspond to a supported IEEE floating-point 2217 * type, an illegal instruction exception is raised. 2218 */ 2219static bool opfvv_check(DisasContext *s, arg_rmrr *a) 2220{ 2221 return require_rvv(s) && 2222 require_rvf(s) && 2223 vext_check_isa_ill(s) && 2224 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2225} 2226 2227/* OPFVV without GVEC IR */ 2228#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2229static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2230{ \ 2231 if (CHECK(s, a)) { \ 2232 uint32_t data = 0; \ 2233 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2234 gen_helper_##NAME##_h, \ 2235 gen_helper_##NAME##_w, \ 2236 gen_helper_##NAME##_d, \ 2237 }; \ 2238 gen_set_rm(s, RISCV_FRM_DYN); \ 2239 \ 2240 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2241 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2242 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2243 data = \ 2244 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 2245 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2246 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2247 vreg_ofs(s, a->rs1), \ 2248 vreg_ofs(s, a->rs2), tcg_env, \ 2249 s->cfg_ptr->vlenb, \ 2250 s->cfg_ptr->vlenb, data, \ 2251 fns[s->sew - 1]); \ 2252 finalize_rvv_inst(s); \ 2253 return true; \ 2254 } \ 2255 return false; \ 2256} 2257GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2258GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2259 2260typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2261 TCGv_env, TCGv_i32); 2262 2263static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2264 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2265{ 2266 TCGv_ptr dest, src2, mask; 2267 TCGv_i32 desc; 2268 TCGv_i64 t1; 2269 2270 dest = tcg_temp_new_ptr(); 2271 mask = tcg_temp_new_ptr(); 2272 src2 = tcg_temp_new_ptr(); 2273 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2274 s->cfg_ptr->vlenb, data)); 2275 2276 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); 2277 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, vs2)); 2278 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 2279 2280 /* NaN-box f[rs1] */ 2281 t1 = tcg_temp_new_i64(); 2282 do_nanbox(s, t1, cpu_fpr[rs1]); 2283 2284 fn(dest, mask, t1, src2, tcg_env, desc); 2285 2286 finalize_rvv_inst(s); 2287 return true; 2288} 2289 2290/* 2291 * If the current SEW does not correspond to a supported IEEE floating-point 2292 * type, an illegal instruction exception is raised 2293 */ 2294static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2295{ 2296 return require_rvv(s) && 2297 require_rvf(s) && 2298 vext_check_isa_ill(s) && 2299 vext_check_ss(s, a->rd, a->rs2, a->vm); 2300} 2301 2302/* OPFVF without GVEC IR */ 2303#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2304static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2305{ \ 2306 if (CHECK(s, a)) { \ 2307 uint32_t data = 0; \ 2308 static gen_helper_opfvf *const fns[3] = { \ 2309 gen_helper_##NAME##_h, \ 2310 gen_helper_##NAME##_w, \ 2311 gen_helper_##NAME##_d, \ 2312 }; \ 2313 gen_set_rm(s, RISCV_FRM_DYN); \ 2314 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2315 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2316 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2317 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \ 2318 s->cfg_vta_all_1s); \ 2319 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2320 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2321 fns[s->sew - 1], s); \ 2322 } \ 2323 return false; \ 2324} 2325 2326GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2327GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2328GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2329 2330/* Vector Widening Floating-Point Add/Subtract Instructions */ 2331static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2332{ 2333 return require_rvv(s) && 2334 require_rvf(s) && 2335 require_scale_rvf(s) && 2336 vext_check_isa_ill(s) && 2337 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2338} 2339 2340/* OPFVV with WIDEN */ 2341#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2342static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2343{ \ 2344 if (CHECK(s, a)) { \ 2345 uint32_t data = 0; \ 2346 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2347 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2348 }; \ 2349 gen_set_rm(s, RISCV_FRM_DYN); \ 2350 \ 2351 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2352 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2353 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2354 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2355 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2356 vreg_ofs(s, a->rs1), \ 2357 vreg_ofs(s, a->rs2), tcg_env, \ 2358 s->cfg_ptr->vlenb, \ 2359 s->cfg_ptr->vlenb, data, \ 2360 fns[s->sew - 1]); \ 2361 finalize_rvv_inst(s); \ 2362 return true; \ 2363 } \ 2364 return false; \ 2365} 2366 2367GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2368GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2369 2370static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2371{ 2372 return require_rvv(s) && 2373 require_rvf(s) && 2374 require_scale_rvf(s) && 2375 vext_check_isa_ill(s) && 2376 vext_check_ds(s, a->rd, a->rs2, a->vm); 2377} 2378 2379/* OPFVF with WIDEN */ 2380#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2381static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2382{ \ 2383 if (opfvf_widen_check(s, a)) { \ 2384 uint32_t data = 0; \ 2385 static gen_helper_opfvf *const fns[2] = { \ 2386 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2387 }; \ 2388 gen_set_rm(s, RISCV_FRM_DYN); \ 2389 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2390 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2391 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2392 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2393 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2394 fns[s->sew - 1], s); \ 2395 } \ 2396 return false; \ 2397} 2398 2399GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2400GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2401 2402static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2403{ 2404 return require_rvv(s) && 2405 require_rvf(s) && 2406 require_scale_rvf(s) && 2407 vext_check_isa_ill(s) && 2408 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2409} 2410 2411/* WIDEN OPFVV with WIDEN */ 2412#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2413static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2414{ \ 2415 if (opfwv_widen_check(s, a)) { \ 2416 uint32_t data = 0; \ 2417 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2418 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2419 }; \ 2420 gen_set_rm(s, RISCV_FRM_DYN); \ 2421 \ 2422 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2423 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2424 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2425 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2426 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2427 vreg_ofs(s, a->rs1), \ 2428 vreg_ofs(s, a->rs2), tcg_env, \ 2429 s->cfg_ptr->vlenb, \ 2430 s->cfg_ptr->vlenb, data, \ 2431 fns[s->sew - 1]); \ 2432 finalize_rvv_inst(s); \ 2433 return true; \ 2434 } \ 2435 return false; \ 2436} 2437 2438GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2439GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2440 2441static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2442{ 2443 return require_rvv(s) && 2444 require_rvf(s) && 2445 require_scale_rvf(s) && 2446 vext_check_isa_ill(s) && 2447 vext_check_dd(s, a->rd, a->rs2, a->vm); 2448} 2449 2450/* WIDEN OPFVF with WIDEN */ 2451#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2452static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2453{ \ 2454 if (opfwf_widen_check(s, a)) { \ 2455 uint32_t data = 0; \ 2456 static gen_helper_opfvf *const fns[2] = { \ 2457 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2458 }; \ 2459 gen_set_rm(s, RISCV_FRM_DYN); \ 2460 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2461 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2462 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2463 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2464 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2465 fns[s->sew - 1], s); \ 2466 } \ 2467 return false; \ 2468} 2469 2470GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2471GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2472 2473/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2474GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2475GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2476GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2477GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2478GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2479 2480/* Vector Widening Floating-Point Multiply */ 2481GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2482GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2483 2484/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2485GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2486GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2487GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2488GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2489GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2490GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2491GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2492GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2493GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2494GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2495GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2496GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2497GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2498GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2499GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2500GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2501 2502/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2503GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2504GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2505GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2506GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2507GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2508GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2509GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2510GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2511 2512/* Vector Floating-Point Square-Root Instruction */ 2513 2514/* 2515 * If the current SEW does not correspond to a supported IEEE floating-point 2516 * type, an illegal instruction exception is raised 2517 */ 2518static bool opfv_check(DisasContext *s, arg_rmr *a) 2519{ 2520 return require_rvv(s) && 2521 require_rvf(s) && 2522 vext_check_isa_ill(s) && 2523 /* OPFV instructions ignore vs1 check */ 2524 vext_check_ss(s, a->rd, a->rs2, a->vm); 2525} 2526 2527static bool do_opfv(DisasContext *s, arg_rmr *a, 2528 gen_helper_gvec_3_ptr *fn, 2529 bool (*checkfn)(DisasContext *, arg_rmr *), 2530 int rm) 2531{ 2532 if (checkfn(s, a)) { 2533 uint32_t data = 0; 2534 gen_set_rm_chkfrm(s, rm); 2535 2536 data = FIELD_DP32(data, VDATA, VM, a->vm); 2537 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2538 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2539 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2540 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2541 vreg_ofs(s, a->rs2), tcg_env, 2542 s->cfg_ptr->vlenb, 2543 s->cfg_ptr->vlenb, data, fn); 2544 finalize_rvv_inst(s); 2545 return true; 2546 } 2547 return false; 2548} 2549 2550#define GEN_OPFV_TRANS(NAME, CHECK, FRM) \ 2551static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2552{ \ 2553 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2554 gen_helper_##NAME##_h, \ 2555 gen_helper_##NAME##_w, \ 2556 gen_helper_##NAME##_d \ 2557 }; \ 2558 return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \ 2559} 2560 2561GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN) 2562GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN) 2563GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN) 2564 2565/* Vector Floating-Point MIN/MAX Instructions */ 2566GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2567GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2568GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2569GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2570 2571/* Vector Floating-Point Sign-Injection Instructions */ 2572GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2573GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2574GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2575GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2576GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2577GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2578 2579/* Vector Floating-Point Compare Instructions */ 2580static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2581{ 2582 return require_rvv(s) && 2583 require_rvf(s) && 2584 vext_check_isa_ill(s) && 2585 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2586} 2587 2588GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2589GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2590GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2591GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2592 2593static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2594{ 2595 return require_rvv(s) && 2596 require_rvf(s) && 2597 vext_check_isa_ill(s) && 2598 vext_check_ms(s, a->rd, a->rs2); 2599} 2600 2601GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2602GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2603GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2604GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2605GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2606GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2607 2608/* Vector Floating-Point Classify Instruction */ 2609GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN) 2610 2611/* Vector Floating-Point Merge Instruction */ 2612GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2613 2614static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2615{ 2616 if (require_rvv(s) && 2617 require_rvf(s) && 2618 vext_check_isa_ill(s) && 2619 require_align(a->rd, s->lmul)) { 2620 gen_set_rm(s, RISCV_FRM_DYN); 2621 2622 TCGv_i64 t1; 2623 2624 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2625 t1 = tcg_temp_new_i64(); 2626 /* NaN-box f[rs1] */ 2627 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2628 2629 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2630 MAXSZ(s), MAXSZ(s), t1); 2631 } else { 2632 TCGv_ptr dest; 2633 TCGv_i32 desc; 2634 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2635 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2636 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2637 static gen_helper_vmv_vx * const fns[3] = { 2638 gen_helper_vmv_v_x_h, 2639 gen_helper_vmv_v_x_w, 2640 gen_helper_vmv_v_x_d, 2641 }; 2642 2643 t1 = tcg_temp_new_i64(); 2644 /* NaN-box f[rs1] */ 2645 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2646 2647 dest = tcg_temp_new_ptr(); 2648 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 2649 s->cfg_ptr->vlenb, data)); 2650 tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, a->rd)); 2651 2652 fns[s->sew - 1](dest, t1, tcg_env, desc); 2653 } 2654 finalize_rvv_inst(s); 2655 return true; 2656 } 2657 return false; 2658} 2659 2660/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2661#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM) \ 2662static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2663{ \ 2664 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2665 gen_helper_##HELPER##_h, \ 2666 gen_helper_##HELPER##_w, \ 2667 gen_helper_##HELPER##_d \ 2668 }; \ 2669 return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \ 2670} 2671 2672GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN) 2673GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN) 2674GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN) 2675GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN) 2676/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */ 2677GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ) 2678GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ) 2679 2680/* Widening Floating-Point/Integer Type-Convert Instructions */ 2681 2682/* 2683 * If the current SEW does not correspond to a supported IEEE floating-point 2684 * type, an illegal instruction exception is raised 2685 */ 2686static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2687{ 2688 return require_rvv(s) && 2689 vext_check_isa_ill(s) && 2690 vext_check_ds(s, a->rd, a->rs2, a->vm); 2691} 2692 2693static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) 2694{ 2695 return opfv_widen_check(s, a) && 2696 require_rvf(s); 2697} 2698 2699static bool opffv_widen_check(DisasContext *s, arg_rmr *a) 2700{ 2701 return opfv_widen_check(s, a) && 2702 require_rvfmin(s) && 2703 require_scale_rvfmin(s); 2704} 2705 2706#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ 2707static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2708{ \ 2709 if (CHECK(s, a)) { \ 2710 uint32_t data = 0; \ 2711 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2712 gen_helper_##HELPER##_h, \ 2713 gen_helper_##HELPER##_w, \ 2714 }; \ 2715 gen_set_rm_chkfrm(s, FRM); \ 2716 \ 2717 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2718 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2719 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2720 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2721 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2722 vreg_ofs(s, a->rs2), tcg_env, \ 2723 s->cfg_ptr->vlenb, \ 2724 s->cfg_ptr->vlenb, data, \ 2725 fns[s->sew - 1]); \ 2726 finalize_rvv_inst(s); \ 2727 return true; \ 2728 } \ 2729 return false; \ 2730} 2731 2732GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2733 RISCV_FRM_DYN) 2734GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2735 RISCV_FRM_DYN) 2736GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v, 2737 RISCV_FRM_DYN) 2738/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2739GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2740 RISCV_FRM_RTZ) 2741GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2742 RISCV_FRM_RTZ) 2743 2744static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2745{ 2746 return require_rvv(s) && 2747 require_scale_rvf(s) && 2748 vext_check_isa_ill(s) && 2749 /* OPFV widening instructions ignore vs1 check */ 2750 vext_check_ds(s, a->rd, a->rs2, a->vm); 2751} 2752 2753#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2754static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2755{ \ 2756 if (opfxv_widen_check(s, a)) { \ 2757 uint32_t data = 0; \ 2758 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2759 gen_helper_##NAME##_b, \ 2760 gen_helper_##NAME##_h, \ 2761 gen_helper_##NAME##_w, \ 2762 }; \ 2763 gen_set_rm(s, RISCV_FRM_DYN); \ 2764 \ 2765 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2766 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2767 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2768 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2769 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2770 vreg_ofs(s, a->rs2), tcg_env, \ 2771 s->cfg_ptr->vlenb, \ 2772 s->cfg_ptr->vlenb, data, \ 2773 fns[s->sew]); \ 2774 finalize_rvv_inst(s); \ 2775 return true; \ 2776 } \ 2777 return false; \ 2778} 2779 2780GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 2781GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 2782 2783/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2784 2785/* 2786 * If the current SEW does not correspond to a supported IEEE floating-point 2787 * type, an illegal instruction exception is raised 2788 */ 2789static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2790{ 2791 return require_rvv(s) && 2792 vext_check_isa_ill(s) && 2793 /* OPFV narrowing instructions ignore vs1 check */ 2794 vext_check_sd(s, a->rd, a->rs2, a->vm); 2795} 2796 2797static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) 2798{ 2799 return opfv_narrow_check(s, a) && 2800 require_rvf(s) && 2801 (s->sew != MO_64); 2802} 2803 2804static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) 2805{ 2806 return opfv_narrow_check(s, a) && 2807 require_rvfmin(s) && 2808 require_scale_rvfmin(s); 2809} 2810 2811static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a) 2812{ 2813 return opfv_narrow_check(s, a) && 2814 require_rvf(s) && 2815 require_scale_rvf(s); 2816} 2817 2818#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ 2819static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2820{ \ 2821 if (CHECK(s, a)) { \ 2822 uint32_t data = 0; \ 2823 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2824 gen_helper_##HELPER##_h, \ 2825 gen_helper_##HELPER##_w, \ 2826 }; \ 2827 gen_set_rm_chkfrm(s, FRM); \ 2828 \ 2829 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2830 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2831 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2832 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2833 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2834 vreg_ofs(s, a->rs2), tcg_env, \ 2835 s->cfg_ptr->vlenb, \ 2836 s->cfg_ptr->vlenb, data, \ 2837 fns[s->sew - 1]); \ 2838 finalize_rvv_inst(s); \ 2839 return true; \ 2840 } \ 2841 return false; \ 2842} 2843 2844GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w, 2845 RISCV_FRM_DYN) 2846GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w, 2847 RISCV_FRM_DYN) 2848GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2849 RISCV_FRM_DYN) 2850/* Reuse the helper function from vfncvt.f.f.w */ 2851GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_rod_narrow_check, vfncvt_f_f_w, 2852 RISCV_FRM_ROD) 2853 2854static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 2855{ 2856 return require_rvv(s) && 2857 require_scale_rvf(s) && 2858 vext_check_isa_ill(s) && 2859 /* OPFV narrowing instructions ignore vs1 check */ 2860 vext_check_sd(s, a->rd, a->rs2, a->vm); 2861} 2862 2863#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2864static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2865{ \ 2866 if (opxfv_narrow_check(s, a)) { \ 2867 uint32_t data = 0; \ 2868 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2869 gen_helper_##HELPER##_b, \ 2870 gen_helper_##HELPER##_h, \ 2871 gen_helper_##HELPER##_w, \ 2872 }; \ 2873 gen_set_rm_chkfrm(s, FRM); \ 2874 \ 2875 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2876 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2877 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2878 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2879 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2880 vreg_ofs(s, a->rs2), tcg_env, \ 2881 s->cfg_ptr->vlenb, \ 2882 s->cfg_ptr->vlenb, data, \ 2883 fns[s->sew]); \ 2884 finalize_rvv_inst(s); \ 2885 return true; \ 2886 } \ 2887 return false; \ 2888} 2889 2890GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 2891GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 2892/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 2893GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 2894GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 2895 2896/* 2897 *** Vector Reduction Operations 2898 */ 2899/* Vector Single-Width Integer Reduction Instructions */ 2900static bool reduction_check(DisasContext *s, arg_rmrr *a) 2901{ 2902 return require_rvv(s) && 2903 vext_check_isa_ill(s) && 2904 vext_check_reduction(s, a->rs2); 2905} 2906 2907GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2908GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2909GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2910GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2911GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2912GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2913GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2914GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2915 2916/* Vector Widening Integer Reduction Instructions */ 2917static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2918{ 2919 return reduction_check(s, a) && (s->sew < MO_64) && 2920 ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)); 2921} 2922 2923GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2924GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2925 2926/* Vector Single-Width Floating-Point Reduction Instructions */ 2927static bool freduction_check(DisasContext *s, arg_rmrr *a) 2928{ 2929 return reduction_check(s, a) && 2930 require_rvf(s); 2931} 2932 2933GEN_OPFVV_TRANS(vfredusum_vs, freduction_check) 2934GEN_OPFVV_TRANS(vfredosum_vs, freduction_check) 2935GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 2936GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 2937 2938/* Vector Widening Floating-Point Reduction Instructions */ 2939static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 2940{ 2941 return reduction_widen_check(s, a) && 2942 require_rvf(s) && 2943 require_scale_rvf(s); 2944} 2945 2946GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) 2947GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check) 2948 2949/* 2950 *** Vector Mask Operations 2951 */ 2952 2953/* Vector Mask-Register Logical Instructions */ 2954#define GEN_MM_TRANS(NAME) \ 2955static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2956{ \ 2957 if (require_rvv(s) && \ 2958 vext_check_isa_ill(s)) { \ 2959 uint32_t data = 0; \ 2960 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2961 \ 2962 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2963 data = \ 2964 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 2965 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2966 vreg_ofs(s, a->rs1), \ 2967 vreg_ofs(s, a->rs2), tcg_env, \ 2968 s->cfg_ptr->vlenb, \ 2969 s->cfg_ptr->vlenb, data, fn); \ 2970 finalize_rvv_inst(s); \ 2971 return true; \ 2972 } \ 2973 return false; \ 2974} 2975 2976GEN_MM_TRANS(vmand_mm) 2977GEN_MM_TRANS(vmnand_mm) 2978GEN_MM_TRANS(vmandn_mm) 2979GEN_MM_TRANS(vmxor_mm) 2980GEN_MM_TRANS(vmor_mm) 2981GEN_MM_TRANS(vmnor_mm) 2982GEN_MM_TRANS(vmorn_mm) 2983GEN_MM_TRANS(vmxnor_mm) 2984 2985/* Vector count population in mask vcpop */ 2986static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 2987{ 2988 if (require_rvv(s) && 2989 vext_check_isa_ill(s) && 2990 s->vstart_eq_zero) { 2991 TCGv_ptr src2, mask; 2992 TCGv dst; 2993 TCGv_i32 desc; 2994 uint32_t data = 0; 2995 data = FIELD_DP32(data, VDATA, VM, a->vm); 2996 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2997 2998 mask = tcg_temp_new_ptr(); 2999 src2 = tcg_temp_new_ptr(); 3000 dst = dest_gpr(s, a->rd); 3001 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 3002 s->cfg_ptr->vlenb, data)); 3003 3004 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); 3005 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 3006 3007 gen_helper_vcpop_m(dst, mask, src2, tcg_env, desc); 3008 gen_set_gpr(s, a->rd, dst); 3009 return true; 3010 } 3011 return false; 3012} 3013 3014/* vmfirst find-first-set mask bit */ 3015static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 3016{ 3017 if (require_rvv(s) && 3018 vext_check_isa_ill(s) && 3019 s->vstart_eq_zero) { 3020 TCGv_ptr src2, mask; 3021 TCGv dst; 3022 TCGv_i32 desc; 3023 uint32_t data = 0; 3024 data = FIELD_DP32(data, VDATA, VM, a->vm); 3025 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3026 3027 mask = tcg_temp_new_ptr(); 3028 src2 = tcg_temp_new_ptr(); 3029 dst = dest_gpr(s, a->rd); 3030 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, 3031 s->cfg_ptr->vlenb, data)); 3032 3033 tcg_gen_addi_ptr(src2, tcg_env, vreg_ofs(s, a->rs2)); 3034 tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); 3035 3036 gen_helper_vfirst_m(dst, mask, src2, tcg_env, desc); 3037 gen_set_gpr(s, a->rd, dst); 3038 return true; 3039 } 3040 return false; 3041} 3042 3043/* 3044 * vmsbf.m set-before-first mask bit 3045 * vmsif.m set-including-first mask bit 3046 * vmsof.m set-only-first mask bit 3047 */ 3048#define GEN_M_TRANS(NAME) \ 3049static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3050{ \ 3051 if (require_rvv(s) && \ 3052 vext_check_isa_ill(s) && \ 3053 require_vm(a->vm, a->rd) && \ 3054 (a->rd != a->rs2) && \ 3055 s->vstart_eq_zero) { \ 3056 uint32_t data = 0; \ 3057 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 3058 \ 3059 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3060 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3061 data = \ 3062 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 3063 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3064 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 3065 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 3066 tcg_env, s->cfg_ptr->vlenb, \ 3067 s->cfg_ptr->vlenb, \ 3068 data, fn); \ 3069 finalize_rvv_inst(s); \ 3070 return true; \ 3071 } \ 3072 return false; \ 3073} 3074 3075GEN_M_TRANS(vmsbf_m) 3076GEN_M_TRANS(vmsif_m) 3077GEN_M_TRANS(vmsof_m) 3078 3079/* 3080 * Vector Iota Instruction 3081 * 3082 * 1. The destination register cannot overlap the source register. 3083 * 2. If masked, cannot overlap the mask register ('v0'). 3084 * 3. An illegal instruction exception is raised if vstart is non-zero. 3085 */ 3086static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 3087{ 3088 if (require_rvv(s) && 3089 vext_check_isa_ill(s) && 3090 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 3091 require_vm(a->vm, a->rd) && 3092 require_align(a->rd, s->lmul) && 3093 s->vstart_eq_zero) { 3094 uint32_t data = 0; 3095 3096 data = FIELD_DP32(data, VDATA, VM, a->vm); 3097 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3098 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3099 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3100 static gen_helper_gvec_3_ptr * const fns[4] = { 3101 gen_helper_viota_m_b, gen_helper_viota_m_h, 3102 gen_helper_viota_m_w, gen_helper_viota_m_d, 3103 }; 3104 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3105 vreg_ofs(s, a->rs2), tcg_env, 3106 s->cfg_ptr->vlenb, 3107 s->cfg_ptr->vlenb, data, fns[s->sew]); 3108 finalize_rvv_inst(s); 3109 return true; 3110 } 3111 return false; 3112} 3113 3114/* Vector Element Index Instruction */ 3115static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3116{ 3117 if (require_rvv(s) && 3118 vext_check_isa_ill(s) && 3119 require_align(a->rd, s->lmul) && 3120 require_vm(a->vm, a->rd)) { 3121 uint32_t data = 0; 3122 3123 data = FIELD_DP32(data, VDATA, VM, a->vm); 3124 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3125 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3126 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3127 static gen_helper_gvec_2_ptr * const fns[4] = { 3128 gen_helper_vid_v_b, gen_helper_vid_v_h, 3129 gen_helper_vid_v_w, gen_helper_vid_v_d, 3130 }; 3131 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3132 tcg_env, s->cfg_ptr->vlenb, 3133 s->cfg_ptr->vlenb, 3134 data, fns[s->sew]); 3135 finalize_rvv_inst(s); 3136 return true; 3137 } 3138 return false; 3139} 3140 3141/* 3142 *** Vector Permutation Instructions 3143 */ 3144 3145static void load_element(TCGv_i64 dest, TCGv_ptr base, 3146 int ofs, int sew, bool sign) 3147{ 3148 switch (sew) { 3149 case MO_8: 3150 if (!sign) { 3151 tcg_gen_ld8u_i64(dest, base, ofs); 3152 } else { 3153 tcg_gen_ld8s_i64(dest, base, ofs); 3154 } 3155 break; 3156 case MO_16: 3157 if (!sign) { 3158 tcg_gen_ld16u_i64(dest, base, ofs); 3159 } else { 3160 tcg_gen_ld16s_i64(dest, base, ofs); 3161 } 3162 break; 3163 case MO_32: 3164 if (!sign) { 3165 tcg_gen_ld32u_i64(dest, base, ofs); 3166 } else { 3167 tcg_gen_ld32s_i64(dest, base, ofs); 3168 } 3169 break; 3170 case MO_64: 3171 tcg_gen_ld_i64(dest, base, ofs); 3172 break; 3173 default: 3174 g_assert_not_reached(); 3175 break; 3176 } 3177} 3178 3179/* offset of the idx element with base register r */ 3180static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3181{ 3182#if HOST_BIG_ENDIAN 3183 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3184#else 3185 return vreg_ofs(s, r) + (idx << s->sew); 3186#endif 3187} 3188 3189/* adjust the index according to the endian */ 3190static void endian_adjust(TCGv_i32 ofs, int sew) 3191{ 3192#if HOST_BIG_ENDIAN 3193 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3194#endif 3195} 3196 3197/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3198static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3199 int vreg, TCGv idx, int vlmax) 3200{ 3201 TCGv_i32 ofs = tcg_temp_new_i32(); 3202 TCGv_ptr base = tcg_temp_new_ptr(); 3203 TCGv_i64 t_idx = tcg_temp_new_i64(); 3204 TCGv_i64 t_vlmax, t_zero; 3205 3206 /* 3207 * Mask the index to the length so that we do 3208 * not produce an out-of-range load. 3209 */ 3210 tcg_gen_trunc_tl_i32(ofs, idx); 3211 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3212 3213 /* Convert the index to an offset. */ 3214 endian_adjust(ofs, s->sew); 3215 tcg_gen_shli_i32(ofs, ofs, s->sew); 3216 3217 /* Convert the index to a pointer. */ 3218 tcg_gen_ext_i32_ptr(base, ofs); 3219 tcg_gen_add_ptr(base, base, tcg_env); 3220 3221 /* Perform the load. */ 3222 load_element(dest, base, 3223 vreg_ofs(s, vreg), s->sew, false); 3224 3225 /* Flush out-of-range indexing to zero. */ 3226 t_vlmax = tcg_constant_i64(vlmax); 3227 t_zero = tcg_constant_i64(0); 3228 tcg_gen_extu_tl_i64(t_idx, idx); 3229 3230 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3231 t_vlmax, dest, t_zero); 3232} 3233 3234static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3235 int vreg, int idx, bool sign) 3236{ 3237 load_element(dest, tcg_env, endian_ofs(s, vreg, idx), s->sew, sign); 3238} 3239 3240/* Integer Scalar Move Instruction */ 3241 3242static void store_element(TCGv_i64 val, TCGv_ptr base, 3243 int ofs, int sew) 3244{ 3245 switch (sew) { 3246 case MO_8: 3247 tcg_gen_st8_i64(val, base, ofs); 3248 break; 3249 case MO_16: 3250 tcg_gen_st16_i64(val, base, ofs); 3251 break; 3252 case MO_32: 3253 tcg_gen_st32_i64(val, base, ofs); 3254 break; 3255 case MO_64: 3256 tcg_gen_st_i64(val, base, ofs); 3257 break; 3258 default: 3259 g_assert_not_reached(); 3260 break; 3261 } 3262} 3263 3264/* 3265 * Store vreg[idx] = val. 3266 * The index must be in range of VLMAX. 3267 */ 3268static void vec_element_storei(DisasContext *s, int vreg, 3269 int idx, TCGv_i64 val) 3270{ 3271 store_element(val, tcg_env, endian_ofs(s, vreg, idx), s->sew); 3272} 3273 3274/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3275static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3276{ 3277 if (require_rvv(s) && 3278 vext_check_isa_ill(s)) { 3279 TCGv_i64 t1; 3280 TCGv dest; 3281 3282 t1 = tcg_temp_new_i64(); 3283 dest = tcg_temp_new(); 3284 /* 3285 * load vreg and sign-extend to 64 bits, 3286 * then truncate to XLEN bits before storing to gpr. 3287 */ 3288 vec_element_loadi(s, t1, a->rs2, 0, true); 3289 tcg_gen_trunc_i64_tl(dest, t1); 3290 gen_set_gpr(s, a->rd, dest); 3291 tcg_gen_movi_tl(cpu_vstart, 0); 3292 finalize_rvv_inst(s); 3293 return true; 3294 } 3295 return false; 3296} 3297 3298/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3299static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3300{ 3301 if (require_rvv(s) && 3302 vext_check_isa_ill(s)) { 3303 /* This instruction ignores LMUL and vector register groups */ 3304 TCGv_i64 t1; 3305 TCGv s1; 3306 TCGLabel *over = gen_new_label(); 3307 3308 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3309 3310 t1 = tcg_temp_new_i64(); 3311 3312 /* 3313 * load gpr and sign-extend to 64 bits, 3314 * then truncate to SEW bits when storing to vreg. 3315 */ 3316 s1 = get_gpr(s, a->rs1, EXT_NONE); 3317 tcg_gen_ext_tl_i64(t1, s1); 3318 vec_element_storei(s, a->rd, 0, t1); 3319 gen_set_label(over); 3320 tcg_gen_movi_tl(cpu_vstart, 0); 3321 finalize_rvv_inst(s); 3322 return true; 3323 } 3324 return false; 3325} 3326 3327/* Floating-Point Scalar Move Instructions */ 3328static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3329{ 3330 if (require_rvv(s) && 3331 require_rvf(s) && 3332 vext_check_isa_ill(s)) { 3333 gen_set_rm(s, RISCV_FRM_DYN); 3334 3335 unsigned int ofs = (8 << s->sew); 3336 unsigned int len = 64 - ofs; 3337 TCGv_i64 t_nan; 3338 3339 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3340 /* NaN-box f[rd] as necessary for SEW */ 3341 if (len) { 3342 t_nan = tcg_constant_i64(UINT64_MAX); 3343 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3344 t_nan, ofs, len); 3345 } 3346 3347 mark_fs_dirty(s); 3348 tcg_gen_movi_tl(cpu_vstart, 0); 3349 finalize_rvv_inst(s); 3350 return true; 3351 } 3352 return false; 3353} 3354 3355/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3356static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3357{ 3358 if (require_rvv(s) && 3359 require_rvf(s) && 3360 vext_check_isa_ill(s)) { 3361 gen_set_rm(s, RISCV_FRM_DYN); 3362 3363 /* The instructions ignore LMUL and vector register group. */ 3364 TCGv_i64 t1; 3365 TCGLabel *over = gen_new_label(); 3366 3367 /* if vstart >= vl, skip vector register write back */ 3368 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3369 3370 /* NaN-box f[rs1] */ 3371 t1 = tcg_temp_new_i64(); 3372 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3373 3374 vec_element_storei(s, a->rd, 0, t1); 3375 3376 gen_set_label(over); 3377 tcg_gen_movi_tl(cpu_vstart, 0); 3378 finalize_rvv_inst(s); 3379 return true; 3380 } 3381 return false; 3382} 3383 3384/* Vector Slide Instructions */ 3385static bool slideup_check(DisasContext *s, arg_rmrr *a) 3386{ 3387 return require_rvv(s) && 3388 vext_check_isa_ill(s) && 3389 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3390} 3391 3392GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3393GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3394GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3395 3396static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3397{ 3398 return require_rvv(s) && 3399 vext_check_isa_ill(s) && 3400 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3401} 3402 3403GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3404GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3405GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3406 3407/* Vector Floating-Point Slide Instructions */ 3408static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3409{ 3410 return slideup_check(s, a) && 3411 require_rvf(s); 3412} 3413 3414static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3415{ 3416 return slidedown_check(s, a) && 3417 require_rvf(s); 3418} 3419 3420GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3421GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3422 3423/* Vector Register Gather Instruction */ 3424static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3425{ 3426 return require_rvv(s) && 3427 vext_check_isa_ill(s) && 3428 require_align(a->rd, s->lmul) && 3429 require_align(a->rs1, s->lmul) && 3430 require_align(a->rs2, s->lmul) && 3431 (a->rd != a->rs2 && a->rd != a->rs1) && 3432 require_vm(a->vm, a->rd); 3433} 3434 3435static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3436{ 3437 int8_t emul = MO_16 - s->sew + s->lmul; 3438 return require_rvv(s) && 3439 vext_check_isa_ill(s) && 3440 (emul >= -3 && emul <= 3) && 3441 require_align(a->rd, s->lmul) && 3442 require_align(a->rs1, emul) && 3443 require_align(a->rs2, s->lmul) && 3444 (a->rd != a->rs2 && a->rd != a->rs1) && 3445 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3446 a->rs1, 1 << MAX(emul, 0)) && 3447 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3448 a->rs2, 1 << MAX(s->lmul, 0)) && 3449 require_vm(a->vm, a->rd); 3450} 3451 3452GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3453GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3454 3455static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3456{ 3457 return require_rvv(s) && 3458 vext_check_isa_ill(s) && 3459 require_align(a->rd, s->lmul) && 3460 require_align(a->rs2, s->lmul) && 3461 (a->rd != a->rs2) && 3462 require_vm(a->vm, a->rd); 3463} 3464 3465/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3466static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3467{ 3468 if (!vrgather_vx_check(s, a)) { 3469 return false; 3470 } 3471 3472 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3473 int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); 3474 TCGv_i64 dest = tcg_temp_new_i64(); 3475 3476 if (a->rs1 == 0) { 3477 vec_element_loadi(s, dest, a->rs2, 0, false); 3478 } else { 3479 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3480 } 3481 3482 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3483 MAXSZ(s), MAXSZ(s), dest); 3484 finalize_rvv_inst(s); 3485 } else { 3486 static gen_helper_opivx * const fns[4] = { 3487 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3488 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3489 }; 3490 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3491 } 3492 return true; 3493} 3494 3495/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3496static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3497{ 3498 if (!vrgather_vx_check(s, a)) { 3499 return false; 3500 } 3501 3502 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3503 int vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, s->sew, s->lmul); 3504 if (a->rs1 >= vlmax) { 3505 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3506 MAXSZ(s), MAXSZ(s), 0); 3507 } else { 3508 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3509 endian_ofs(s, a->rs2, a->rs1), 3510 MAXSZ(s), MAXSZ(s)); 3511 } 3512 finalize_rvv_inst(s); 3513 } else { 3514 static gen_helper_opivx * const fns[4] = { 3515 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3516 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3517 }; 3518 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3519 s, IMM_ZX); 3520 } 3521 return true; 3522} 3523 3524/* 3525 * Vector Compress Instruction 3526 * 3527 * The destination vector register group cannot overlap the 3528 * source vector register group or the source mask register. 3529 */ 3530static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3531{ 3532 return require_rvv(s) && 3533 vext_check_isa_ill(s) && 3534 require_align(a->rd, s->lmul) && 3535 require_align(a->rs2, s->lmul) && 3536 (a->rd != a->rs2) && 3537 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3538 s->vstart_eq_zero; 3539} 3540 3541static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3542{ 3543 if (vcompress_vm_check(s, a)) { 3544 uint32_t data = 0; 3545 static gen_helper_gvec_4_ptr * const fns[4] = { 3546 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3547 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3548 }; 3549 3550 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3551 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3552 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3553 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3554 tcg_env, s->cfg_ptr->vlenb, 3555 s->cfg_ptr->vlenb, data, 3556 fns[s->sew]); 3557 finalize_rvv_inst(s); 3558 return true; 3559 } 3560 return false; 3561} 3562 3563/* 3564 * Whole Vector Register Move Instructions depend on vtype register(vsew). 3565 * Thus, we need to check vill bit. (Section 16.6) 3566 */ 3567#define GEN_VMV_WHOLE_TRANS(NAME, LEN) \ 3568static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3569{ \ 3570 if (require_rvv(s) && \ 3571 vext_check_isa_ill(s) && \ 3572 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3573 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3574 uint32_t maxsz = s->cfg_ptr->vlenb * LEN; \ 3575 if (s->vstart_eq_zero) { \ 3576 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), \ 3577 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3578 } else { \ 3579 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3580 tcg_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ 3581 } \ 3582 finalize_rvv_inst(s); \ 3583 return true; \ 3584 } \ 3585 return false; \ 3586} 3587 3588GEN_VMV_WHOLE_TRANS(vmv1r_v, 1) 3589GEN_VMV_WHOLE_TRANS(vmv2r_v, 2) 3590GEN_VMV_WHOLE_TRANS(vmv4r_v, 4) 3591GEN_VMV_WHOLE_TRANS(vmv8r_v, 8) 3592 3593static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3594{ 3595 uint8_t from = (s->sew + 3) - div; 3596 bool ret = require_rvv(s) && 3597 (from >= 3 && from <= 8) && 3598 (a->rd != a->rs2) && 3599 require_align(a->rd, s->lmul) && 3600 require_align(a->rs2, s->lmul - div) && 3601 require_vm(a->vm, a->rd) && 3602 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3603 return ret; 3604} 3605 3606static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3607{ 3608 uint32_t data = 0; 3609 gen_helper_gvec_3_ptr *fn; 3610 3611 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3612 { 3613 NULL, gen_helper_vzext_vf2_h, 3614 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3615 }, 3616 { 3617 NULL, NULL, 3618 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3619 }, 3620 { 3621 NULL, NULL, 3622 NULL, gen_helper_vzext_vf8_d 3623 }, 3624 { 3625 NULL, gen_helper_vsext_vf2_h, 3626 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3627 }, 3628 { 3629 NULL, NULL, 3630 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3631 }, 3632 { 3633 NULL, NULL, 3634 NULL, gen_helper_vsext_vf8_d 3635 } 3636 }; 3637 3638 fn = fns[seq][s->sew]; 3639 if (fn == NULL) { 3640 return false; 3641 } 3642 3643 data = FIELD_DP32(data, VDATA, VM, a->vm); 3644 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3645 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3646 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3647 3648 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3649 vreg_ofs(s, a->rs2), tcg_env, 3650 s->cfg_ptr->vlenb, 3651 s->cfg_ptr->vlenb, data, fn); 3652 3653 finalize_rvv_inst(s); 3654 return true; 3655} 3656 3657/* Vector Integer Extension */ 3658#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3659static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3660{ \ 3661 if (int_ext_check(s, a, DIV)) { \ 3662 return int_ext_op(s, a, SEQ); \ 3663 } \ 3664 return false; \ 3665} 3666 3667GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3668GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3669GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3670GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3671GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3672GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3673