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