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 */ 1911GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1912GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1913GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1914GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1915GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1916GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1917GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1918GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1919 1920/* Vector Integer Divide Instructions */ 1921GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1922GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1923GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1924GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1925GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1926GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1927GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1928GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1929 1930/* Vector Widening Integer Multiply Instructions */ 1931GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1932GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1933GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1934GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1935GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1936GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1937 1938/* Vector Single-Width Integer Multiply-Add Instructions */ 1939GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1940GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1941GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1942GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1943GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1944GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1945GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1946GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1947 1948/* Vector Widening Integer Multiply-Add Instructions */ 1949GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1950GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1951GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1952GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1953GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1954GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1955GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1956 1957/* Vector Integer Merge and Move Instructions */ 1958static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1959{ 1960 if (require_rvv(s) && 1961 vext_check_isa_ill(s) && 1962 /* vmv.v.v has rs2 = 0 and vm = 1 */ 1963 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 1964 if (s->vl_eq_vlmax) { 1965 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1966 vreg_ofs(s, a->rs1), 1967 MAXSZ(s), MAXSZ(s)); 1968 } else { 1969 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1970 static gen_helper_gvec_2_ptr * const fns[4] = { 1971 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1972 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1973 }; 1974 TCGLabel *over = gen_new_label(); 1975 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1976 1977 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1978 cpu_env, s->vlen / 8, s->vlen / 8, data, 1979 fns[s->sew]); 1980 gen_set_label(over); 1981 } 1982 mark_vs_dirty(s); 1983 return true; 1984 } 1985 return false; 1986} 1987 1988typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1989static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1990{ 1991 if (require_rvv(s) && 1992 vext_check_isa_ill(s) && 1993 /* vmv.v.x has rs2 = 0 and vm = 1 */ 1994 vext_check_ss(s, a->rd, 0, 1)) { 1995 TCGv s1; 1996 TCGLabel *over = gen_new_label(); 1997 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1998 1999 s1 = get_gpr(s, a->rs1, EXT_SIGN); 2000 2001 if (s->vl_eq_vlmax) { 2002 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 2003 MAXSZ(s), MAXSZ(s), s1); 2004 } else { 2005 TCGv_i32 desc; 2006 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2007 TCGv_ptr dest = tcg_temp_new_ptr(); 2008 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2009 static gen_helper_vmv_vx * const fns[4] = { 2010 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2011 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2012 }; 2013 2014 tcg_gen_ext_tl_i64(s1_i64, s1); 2015 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2016 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2017 fns[s->sew](dest, s1_i64, cpu_env, desc); 2018 2019 tcg_temp_free_ptr(dest); 2020 tcg_temp_free_i64(s1_i64); 2021 } 2022 2023 mark_vs_dirty(s); 2024 gen_set_label(over); 2025 return true; 2026 } 2027 return false; 2028} 2029 2030static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 2031{ 2032 if (require_rvv(s) && 2033 vext_check_isa_ill(s) && 2034 /* vmv.v.i has rs2 = 0 and vm = 1 */ 2035 vext_check_ss(s, a->rd, 0, 1)) { 2036 int64_t simm = sextract64(a->rs1, 0, 5); 2037 if (s->vl_eq_vlmax) { 2038 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 2039 MAXSZ(s), MAXSZ(s), simm); 2040 mark_vs_dirty(s); 2041 } else { 2042 TCGv_i32 desc; 2043 TCGv_i64 s1; 2044 TCGv_ptr dest; 2045 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2046 static gen_helper_vmv_vx * const fns[4] = { 2047 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2048 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2049 }; 2050 TCGLabel *over = gen_new_label(); 2051 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2052 2053 s1 = tcg_constant_i64(simm); 2054 dest = tcg_temp_new_ptr(); 2055 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2056 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2057 fns[s->sew](dest, s1, cpu_env, desc); 2058 2059 tcg_temp_free_ptr(dest); 2060 mark_vs_dirty(s); 2061 gen_set_label(over); 2062 } 2063 return true; 2064 } 2065 return false; 2066} 2067 2068GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 2069GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 2070GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 2071 2072/* 2073 *** Vector Fixed-Point Arithmetic Instructions 2074 */ 2075 2076/* Vector Single-Width Saturating Add and Subtract */ 2077GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 2078GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 2079GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 2080GEN_OPIVV_TRANS(vssub_vv, opivv_check) 2081GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 2082GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 2083GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 2084GEN_OPIVX_TRANS(vssub_vx, opivx_check) 2085GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check) 2086GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 2087 2088/* Vector Single-Width Averaging Add and Subtract */ 2089GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 2090GEN_OPIVV_TRANS(vaaddu_vv, opivv_check) 2091GEN_OPIVV_TRANS(vasub_vv, opivv_check) 2092GEN_OPIVV_TRANS(vasubu_vv, opivv_check) 2093GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 2094GEN_OPIVX_TRANS(vaaddu_vx, opivx_check) 2095GEN_OPIVX_TRANS(vasub_vx, opivx_check) 2096GEN_OPIVX_TRANS(vasubu_vx, opivx_check) 2097 2098/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 2099GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 2100GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 2101 2102/* Vector Single-Width Scaling Shift Instructions */ 2103GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 2104GEN_OPIVV_TRANS(vssra_vv, opivv_check) 2105GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 2106GEN_OPIVX_TRANS(vssra_vx, opivx_check) 2107GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check) 2108GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check) 2109 2110/* Vector Narrowing Fixed-Point Clip Instructions */ 2111GEN_OPIWV_NARROW_TRANS(vnclipu_wv) 2112GEN_OPIWV_NARROW_TRANS(vnclip_wv) 2113GEN_OPIWX_NARROW_TRANS(vnclipu_wx) 2114GEN_OPIWX_NARROW_TRANS(vnclip_wx) 2115GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx) 2116GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx) 2117 2118/* 2119 *** Vector Float Point Arithmetic Instructions 2120 */ 2121 2122/* 2123 * As RVF-only cpus always have values NaN-boxed to 64-bits, 2124 * RVF and RVD can be treated equally. 2125 * We don't have to deal with the cases of: SEW > FLEN. 2126 * 2127 * If SEW < FLEN, check whether input fp register is a valid 2128 * NaN-boxed value, in which case the least-significant SEW bits 2129 * of the f regsiter are used, else the canonical NaN value is used. 2130 */ 2131static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 2132{ 2133 switch (s->sew) { 2134 case 1: 2135 gen_check_nanbox_h(out, in); 2136 break; 2137 case 2: 2138 gen_check_nanbox_s(out, in); 2139 break; 2140 case 3: 2141 tcg_gen_mov_i64(out, in); 2142 break; 2143 default: 2144 g_assert_not_reached(); 2145 } 2146} 2147 2148/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 2149 2150/* 2151 * If the current SEW does not correspond to a supported IEEE floating-point 2152 * type, an illegal instruction exception is raised. 2153 */ 2154static bool opfvv_check(DisasContext *s, arg_rmrr *a) 2155{ 2156 return require_rvv(s) && 2157 require_rvf(s) && 2158 vext_check_isa_ill(s) && 2159 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2160} 2161 2162/* OPFVV without GVEC IR */ 2163#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2164static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2165{ \ 2166 if (CHECK(s, a)) { \ 2167 uint32_t data = 0; \ 2168 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2169 gen_helper_##NAME##_h, \ 2170 gen_helper_##NAME##_w, \ 2171 gen_helper_##NAME##_d, \ 2172 }; \ 2173 TCGLabel *over = gen_new_label(); \ 2174 gen_set_rm(s, RISCV_FRM_DYN); \ 2175 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2176 \ 2177 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2178 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2179 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2180 vreg_ofs(s, a->rs1), \ 2181 vreg_ofs(s, a->rs2), cpu_env, \ 2182 s->vlen / 8, s->vlen / 8, data, \ 2183 fns[s->sew - 1]); \ 2184 mark_vs_dirty(s); \ 2185 gen_set_label(over); \ 2186 return true; \ 2187 } \ 2188 return false; \ 2189} 2190GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2191GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2192 2193typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2194 TCGv_env, TCGv_i32); 2195 2196static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2197 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2198{ 2199 TCGv_ptr dest, src2, mask; 2200 TCGv_i32 desc; 2201 TCGv_i64 t1; 2202 2203 TCGLabel *over = gen_new_label(); 2204 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2205 2206 dest = tcg_temp_new_ptr(); 2207 mask = tcg_temp_new_ptr(); 2208 src2 = tcg_temp_new_ptr(); 2209 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2210 2211 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 2212 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 2213 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2214 2215 /* NaN-box f[rs1] */ 2216 t1 = tcg_temp_new_i64(); 2217 do_nanbox(s, t1, cpu_fpr[rs1]); 2218 2219 fn(dest, mask, t1, src2, cpu_env, desc); 2220 2221 tcg_temp_free_ptr(dest); 2222 tcg_temp_free_ptr(mask); 2223 tcg_temp_free_ptr(src2); 2224 tcg_temp_free_i64(t1); 2225 mark_vs_dirty(s); 2226 gen_set_label(over); 2227 return true; 2228} 2229 2230/* 2231 * If the current SEW does not correspond to a supported IEEE floating-point 2232 * type, an illegal instruction exception is raised 2233 */ 2234static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2235{ 2236 return require_rvv(s) && 2237 require_rvf(s) && 2238 vext_check_isa_ill(s) && 2239 vext_check_ss(s, a->rd, a->rs2, a->vm); 2240} 2241 2242/* OPFVF without GVEC IR */ 2243#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2244static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2245{ \ 2246 if (CHECK(s, a)) { \ 2247 uint32_t data = 0; \ 2248 static gen_helper_opfvf *const fns[3] = { \ 2249 gen_helper_##NAME##_h, \ 2250 gen_helper_##NAME##_w, \ 2251 gen_helper_##NAME##_d, \ 2252 }; \ 2253 gen_set_rm(s, RISCV_FRM_DYN); \ 2254 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2255 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2256 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2257 fns[s->sew - 1], s); \ 2258 } \ 2259 return false; \ 2260} 2261 2262GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2263GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2264GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2265 2266/* Vector Widening Floating-Point Add/Subtract Instructions */ 2267static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2268{ 2269 return require_rvv(s) && 2270 require_scale_rvf(s) && 2271 (s->sew != MO_8) && 2272 vext_check_isa_ill(s) && 2273 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2274} 2275 2276/* OPFVV with WIDEN */ 2277#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2278static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2279{ \ 2280 if (CHECK(s, a)) { \ 2281 uint32_t data = 0; \ 2282 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2283 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2284 }; \ 2285 TCGLabel *over = gen_new_label(); \ 2286 gen_set_rm(s, RISCV_FRM_DYN); \ 2287 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2288 \ 2289 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2290 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2291 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2292 vreg_ofs(s, a->rs1), \ 2293 vreg_ofs(s, a->rs2), cpu_env, \ 2294 s->vlen / 8, s->vlen / 8, data, \ 2295 fns[s->sew - 1]); \ 2296 mark_vs_dirty(s); \ 2297 gen_set_label(over); \ 2298 return true; \ 2299 } \ 2300 return false; \ 2301} 2302 2303GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2304GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2305 2306static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2307{ 2308 return require_rvv(s) && 2309 require_scale_rvf(s) && 2310 (s->sew != MO_8) && 2311 vext_check_isa_ill(s) && 2312 vext_check_ds(s, a->rd, a->rs2, a->vm); 2313} 2314 2315/* OPFVF with WIDEN */ 2316#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2317static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2318{ \ 2319 if (opfvf_widen_check(s, a)) { \ 2320 uint32_t data = 0; \ 2321 static gen_helper_opfvf *const fns[2] = { \ 2322 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2323 }; \ 2324 gen_set_rm(s, RISCV_FRM_DYN); \ 2325 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2326 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2327 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2328 fns[s->sew - 1], s); \ 2329 } \ 2330 return false; \ 2331} 2332 2333GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2334GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2335 2336static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2337{ 2338 return require_rvv(s) && 2339 require_scale_rvf(s) && 2340 (s->sew != MO_8) && 2341 vext_check_isa_ill(s) && 2342 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2343} 2344 2345/* WIDEN OPFVV with WIDEN */ 2346#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2347static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2348{ \ 2349 if (opfwv_widen_check(s, a)) { \ 2350 uint32_t data = 0; \ 2351 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2352 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2353 }; \ 2354 TCGLabel *over = gen_new_label(); \ 2355 gen_set_rm(s, RISCV_FRM_DYN); \ 2356 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2357 \ 2358 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2359 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2360 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2361 vreg_ofs(s, a->rs1), \ 2362 vreg_ofs(s, a->rs2), cpu_env, \ 2363 s->vlen / 8, s->vlen / 8, data, \ 2364 fns[s->sew - 1]); \ 2365 mark_vs_dirty(s); \ 2366 gen_set_label(over); \ 2367 return true; \ 2368 } \ 2369 return false; \ 2370} 2371 2372GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2373GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2374 2375static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2376{ 2377 return require_rvv(s) && 2378 require_scale_rvf(s) && 2379 (s->sew != MO_8) && 2380 vext_check_isa_ill(s) && 2381 vext_check_dd(s, a->rd, a->rs2, a->vm); 2382} 2383 2384/* WIDEN OPFVF with WIDEN */ 2385#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2386static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2387{ \ 2388 if (opfwf_widen_check(s, a)) { \ 2389 uint32_t data = 0; \ 2390 static gen_helper_opfvf *const fns[2] = { \ 2391 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2392 }; \ 2393 gen_set_rm(s, RISCV_FRM_DYN); \ 2394 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2395 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2396 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2397 fns[s->sew - 1], s); \ 2398 } \ 2399 return false; \ 2400} 2401 2402GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2403GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2404 2405/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2406GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2407GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2408GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2409GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2410GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2411 2412/* Vector Widening Floating-Point Multiply */ 2413GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2414GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2415 2416/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2417GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2418GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2419GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2420GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2421GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2422GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2423GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2424GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2425GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2426GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2427GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2428GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2429GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2430GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2431GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2432GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2433 2434/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2435GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2436GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2437GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2438GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2439GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2440GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2441GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2442GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2443 2444/* Vector Floating-Point Square-Root Instruction */ 2445 2446/* 2447 * If the current SEW does not correspond to a supported IEEE floating-point 2448 * type, an illegal instruction exception is raised 2449 */ 2450static bool opfv_check(DisasContext *s, arg_rmr *a) 2451{ 2452 return require_rvv(s) && 2453 require_rvf(s) && 2454 vext_check_isa_ill(s) && 2455 /* OPFV instructions ignore vs1 check */ 2456 vext_check_ss(s, a->rd, a->rs2, a->vm); 2457} 2458 2459static bool do_opfv(DisasContext *s, arg_rmr *a, 2460 gen_helper_gvec_3_ptr *fn, 2461 bool (*checkfn)(DisasContext *, arg_rmr *), 2462 int rm) 2463{ 2464 if (checkfn(s, a)) { 2465 if (rm != RISCV_FRM_DYN) { 2466 gen_set_rm(s, RISCV_FRM_DYN); 2467 } 2468 2469 uint32_t data = 0; 2470 TCGLabel *over = gen_new_label(); 2471 gen_set_rm(s, rm); 2472 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2473 2474 data = FIELD_DP32(data, VDATA, VM, a->vm); 2475 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2476 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2477 vreg_ofs(s, a->rs2), cpu_env, 2478 s->vlen / 8, s->vlen / 8, data, fn); 2479 mark_vs_dirty(s); 2480 gen_set_label(over); 2481 return true; 2482 } 2483 return false; 2484} 2485 2486#define GEN_OPFV_TRANS(NAME, CHECK, FRM) \ 2487static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2488{ \ 2489 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2490 gen_helper_##NAME##_h, \ 2491 gen_helper_##NAME##_w, \ 2492 gen_helper_##NAME##_d \ 2493 }; \ 2494 return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \ 2495} 2496 2497GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN) 2498GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN) 2499GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN) 2500 2501/* Vector Floating-Point MIN/MAX Instructions */ 2502GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2503GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2504GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2505GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2506 2507/* Vector Floating-Point Sign-Injection Instructions */ 2508GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2509GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2510GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2511GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2512GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2513GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2514 2515/* Vector Floating-Point Compare Instructions */ 2516static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2517{ 2518 return require_rvv(s) && 2519 require_rvf(s) && 2520 vext_check_isa_ill(s) && 2521 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2522} 2523 2524GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2525GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2526GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2527GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2528 2529static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2530{ 2531 return require_rvv(s) && 2532 require_rvf(s) && 2533 vext_check_isa_ill(s) && 2534 vext_check_ms(s, a->rd, a->rs2); 2535} 2536 2537GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2538GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2539GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2540GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2541GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2542GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2543 2544/* Vector Floating-Point Classify Instruction */ 2545GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN) 2546 2547/* Vector Floating-Point Merge Instruction */ 2548GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2549 2550static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2551{ 2552 if (require_rvv(s) && 2553 require_rvf(s) && 2554 vext_check_isa_ill(s) && 2555 require_align(a->rd, s->lmul)) { 2556 gen_set_rm(s, RISCV_FRM_DYN); 2557 2558 TCGv_i64 t1; 2559 2560 if (s->vl_eq_vlmax) { 2561 t1 = tcg_temp_new_i64(); 2562 /* NaN-box f[rs1] */ 2563 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2564 2565 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2566 MAXSZ(s), MAXSZ(s), t1); 2567 mark_vs_dirty(s); 2568 } else { 2569 TCGv_ptr dest; 2570 TCGv_i32 desc; 2571 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2572 static gen_helper_vmv_vx * const fns[3] = { 2573 gen_helper_vmv_v_x_h, 2574 gen_helper_vmv_v_x_w, 2575 gen_helper_vmv_v_x_d, 2576 }; 2577 TCGLabel *over = gen_new_label(); 2578 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2579 2580 t1 = tcg_temp_new_i64(); 2581 /* NaN-box f[rs1] */ 2582 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2583 2584 dest = tcg_temp_new_ptr(); 2585 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2586 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2587 2588 fns[s->sew - 1](dest, t1, cpu_env, desc); 2589 2590 tcg_temp_free_ptr(dest); 2591 mark_vs_dirty(s); 2592 gen_set_label(over); 2593 } 2594 tcg_temp_free_i64(t1); 2595 return true; 2596 } 2597 return false; 2598} 2599 2600/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2601#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM) \ 2602static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2603{ \ 2604 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2605 gen_helper_##HELPER##_h, \ 2606 gen_helper_##HELPER##_w, \ 2607 gen_helper_##HELPER##_d \ 2608 }; \ 2609 return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \ 2610} 2611 2612GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN) 2613GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN) 2614GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN) 2615GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN) 2616/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */ 2617GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ) 2618GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ) 2619 2620/* Widening Floating-Point/Integer Type-Convert Instructions */ 2621 2622/* 2623 * If the current SEW does not correspond to a supported IEEE floating-point 2624 * type, an illegal instruction exception is raised 2625 */ 2626static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2627{ 2628 return require_rvv(s) && 2629 vext_check_isa_ill(s) && 2630 vext_check_ds(s, a->rd, a->rs2, a->vm); 2631} 2632 2633static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) 2634{ 2635 return opfv_widen_check(s, a) && 2636 require_rvf(s); 2637} 2638 2639static bool opffv_widen_check(DisasContext *s, arg_rmr *a) 2640{ 2641 return opfv_widen_check(s, a) && 2642 require_scale_rvf(s) && 2643 (s->sew != MO_8); 2644} 2645 2646#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ 2647static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2648{ \ 2649 if (CHECK(s, a)) { \ 2650 if (FRM != RISCV_FRM_DYN) { \ 2651 gen_set_rm(s, RISCV_FRM_DYN); \ 2652 } \ 2653 \ 2654 uint32_t data = 0; \ 2655 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2656 gen_helper_##HELPER##_h, \ 2657 gen_helper_##HELPER##_w, \ 2658 }; \ 2659 TCGLabel *over = gen_new_label(); \ 2660 gen_set_rm(s, FRM); \ 2661 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2662 \ 2663 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2664 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2665 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2666 vreg_ofs(s, a->rs2), cpu_env, \ 2667 s->vlen / 8, s->vlen / 8, data, \ 2668 fns[s->sew - 1]); \ 2669 mark_vs_dirty(s); \ 2670 gen_set_label(over); \ 2671 return true; \ 2672 } \ 2673 return false; \ 2674} 2675 2676GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2677 RISCV_FRM_DYN) 2678GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2679 RISCV_FRM_DYN) 2680GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v, 2681 RISCV_FRM_DYN) 2682/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2683GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2684 RISCV_FRM_RTZ) 2685GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2686 RISCV_FRM_RTZ) 2687 2688static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2689{ 2690 return require_rvv(s) && 2691 require_scale_rvf(s) && 2692 vext_check_isa_ill(s) && 2693 /* OPFV widening instructions ignore vs1 check */ 2694 vext_check_ds(s, a->rd, a->rs2, a->vm); 2695} 2696 2697#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2698static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2699{ \ 2700 if (opfxv_widen_check(s, a)) { \ 2701 uint32_t data = 0; \ 2702 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2703 gen_helper_##NAME##_b, \ 2704 gen_helper_##NAME##_h, \ 2705 gen_helper_##NAME##_w, \ 2706 }; \ 2707 TCGLabel *over = gen_new_label(); \ 2708 gen_set_rm(s, RISCV_FRM_DYN); \ 2709 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2710 \ 2711 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2712 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2713 vreg_ofs(s, a->rs2), cpu_env, \ 2714 s->vlen / 8, s->vlen / 8, data, \ 2715 fns[s->sew]); \ 2716 mark_vs_dirty(s); \ 2717 gen_set_label(over); \ 2718 return true; \ 2719 } \ 2720 return false; \ 2721} 2722 2723GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 2724GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 2725 2726/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2727 2728/* 2729 * If the current SEW does not correspond to a supported IEEE floating-point 2730 * type, an illegal instruction exception is raised 2731 */ 2732static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2733{ 2734 return require_rvv(s) && 2735 vext_check_isa_ill(s) && 2736 /* OPFV narrowing instructions ignore vs1 check */ 2737 vext_check_sd(s, a->rd, a->rs2, a->vm); 2738} 2739 2740static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) 2741{ 2742 return opfv_narrow_check(s, a) && 2743 require_rvf(s) && 2744 (s->sew != MO_64); 2745} 2746 2747static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) 2748{ 2749 return opfv_narrow_check(s, a) && 2750 require_scale_rvf(s) && 2751 (s->sew != MO_8); 2752} 2753 2754#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ 2755static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2756{ \ 2757 if (CHECK(s, a)) { \ 2758 if (FRM != RISCV_FRM_DYN) { \ 2759 gen_set_rm(s, RISCV_FRM_DYN); \ 2760 } \ 2761 \ 2762 uint32_t data = 0; \ 2763 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2764 gen_helper_##HELPER##_h, \ 2765 gen_helper_##HELPER##_w, \ 2766 }; \ 2767 TCGLabel *over = gen_new_label(); \ 2768 gen_set_rm(s, FRM); \ 2769 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2770 \ 2771 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2772 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2773 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2774 vreg_ofs(s, a->rs2), cpu_env, \ 2775 s->vlen / 8, s->vlen / 8, data, \ 2776 fns[s->sew - 1]); \ 2777 mark_vs_dirty(s); \ 2778 gen_set_label(over); \ 2779 return true; \ 2780 } \ 2781 return false; \ 2782} 2783 2784GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w, 2785 RISCV_FRM_DYN) 2786GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w, 2787 RISCV_FRM_DYN) 2788GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2789 RISCV_FRM_DYN) 2790/* Reuse the helper function from vfncvt.f.f.w */ 2791GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2792 RISCV_FRM_ROD) 2793 2794static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 2795{ 2796 return require_rvv(s) && 2797 require_scale_rvf(s) && 2798 vext_check_isa_ill(s) && 2799 /* OPFV narrowing instructions ignore vs1 check */ 2800 vext_check_sd(s, a->rd, a->rs2, a->vm); 2801} 2802 2803#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2804static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2805{ \ 2806 if (opxfv_narrow_check(s, a)) { \ 2807 if (FRM != RISCV_FRM_DYN) { \ 2808 gen_set_rm(s, RISCV_FRM_DYN); \ 2809 } \ 2810 \ 2811 uint32_t data = 0; \ 2812 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2813 gen_helper_##HELPER##_b, \ 2814 gen_helper_##HELPER##_h, \ 2815 gen_helper_##HELPER##_w, \ 2816 }; \ 2817 TCGLabel *over = gen_new_label(); \ 2818 gen_set_rm(s, FRM); \ 2819 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2820 \ 2821 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2822 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2823 vreg_ofs(s, a->rs2), cpu_env, \ 2824 s->vlen / 8, s->vlen / 8, data, \ 2825 fns[s->sew]); \ 2826 mark_vs_dirty(s); \ 2827 gen_set_label(over); \ 2828 return true; \ 2829 } \ 2830 return false; \ 2831} 2832 2833GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 2834GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 2835/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 2836GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 2837GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 2838 2839/* 2840 *** Vector Reduction Operations 2841 */ 2842/* Vector Single-Width Integer Reduction Instructions */ 2843static bool reduction_check(DisasContext *s, arg_rmrr *a) 2844{ 2845 return require_rvv(s) && 2846 vext_check_isa_ill(s) && 2847 vext_check_reduction(s, a->rs2); 2848} 2849 2850GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2851GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2852GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2853GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2854GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2855GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2856GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2857GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2858 2859/* Vector Widening Integer Reduction Instructions */ 2860static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2861{ 2862 return reduction_check(s, a) && (s->sew < MO_64) && 2863 ((s->sew + 1) <= (s->elen >> 4)); 2864} 2865 2866GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2867GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2868 2869/* Vector Single-Width Floating-Point Reduction Instructions */ 2870static bool freduction_check(DisasContext *s, arg_rmrr *a) 2871{ 2872 return reduction_check(s, a) && 2873 require_rvf(s); 2874} 2875 2876GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) 2877GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 2878GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 2879 2880/* Vector Widening Floating-Point Reduction Instructions */ 2881static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 2882{ 2883 return reduction_widen_check(s, a) && 2884 require_scale_rvf(s) && 2885 (s->sew != MO_8); 2886} 2887 2888GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check) 2889 2890/* 2891 *** Vector Mask Operations 2892 */ 2893 2894/* Vector Mask-Register Logical Instructions */ 2895#define GEN_MM_TRANS(NAME) \ 2896static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2897{ \ 2898 if (require_rvv(s) && \ 2899 vext_check_isa_ill(s)) { \ 2900 uint32_t data = 0; \ 2901 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2902 TCGLabel *over = gen_new_label(); \ 2903 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2904 \ 2905 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2906 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2907 vreg_ofs(s, a->rs1), \ 2908 vreg_ofs(s, a->rs2), cpu_env, \ 2909 s->vlen / 8, s->vlen / 8, data, fn); \ 2910 mark_vs_dirty(s); \ 2911 gen_set_label(over); \ 2912 return true; \ 2913 } \ 2914 return false; \ 2915} 2916 2917GEN_MM_TRANS(vmand_mm) 2918GEN_MM_TRANS(vmnand_mm) 2919GEN_MM_TRANS(vmandn_mm) 2920GEN_MM_TRANS(vmxor_mm) 2921GEN_MM_TRANS(vmor_mm) 2922GEN_MM_TRANS(vmnor_mm) 2923GEN_MM_TRANS(vmorn_mm) 2924GEN_MM_TRANS(vmxnor_mm) 2925 2926/* Vector count population in mask vcpop */ 2927static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 2928{ 2929 if (require_rvv(s) && 2930 vext_check_isa_ill(s) && 2931 s->vstart == 0) { 2932 TCGv_ptr src2, mask; 2933 TCGv dst; 2934 TCGv_i32 desc; 2935 uint32_t data = 0; 2936 data = FIELD_DP32(data, VDATA, VM, a->vm); 2937 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2938 2939 mask = tcg_temp_new_ptr(); 2940 src2 = tcg_temp_new_ptr(); 2941 dst = dest_gpr(s, a->rd); 2942 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2943 2944 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2945 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2946 2947 gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc); 2948 gen_set_gpr(s, a->rd, dst); 2949 2950 tcg_temp_free_ptr(mask); 2951 tcg_temp_free_ptr(src2); 2952 2953 return true; 2954 } 2955 return false; 2956} 2957 2958/* vmfirst find-first-set mask bit */ 2959static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 2960{ 2961 if (require_rvv(s) && 2962 vext_check_isa_ill(s) && 2963 s->vstart == 0) { 2964 TCGv_ptr src2, mask; 2965 TCGv dst; 2966 TCGv_i32 desc; 2967 uint32_t data = 0; 2968 data = FIELD_DP32(data, VDATA, VM, a->vm); 2969 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2970 2971 mask = tcg_temp_new_ptr(); 2972 src2 = tcg_temp_new_ptr(); 2973 dst = dest_gpr(s, a->rd); 2974 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2975 2976 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2977 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2978 2979 gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); 2980 gen_set_gpr(s, a->rd, dst); 2981 2982 tcg_temp_free_ptr(mask); 2983 tcg_temp_free_ptr(src2); 2984 return true; 2985 } 2986 return false; 2987} 2988 2989/* vmsbf.m set-before-first mask bit */ 2990/* vmsif.m set-includ-first mask bit */ 2991/* vmsof.m set-only-first mask bit */ 2992#define GEN_M_TRANS(NAME) \ 2993static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2994{ \ 2995 if (require_rvv(s) && \ 2996 vext_check_isa_ill(s) && \ 2997 require_vm(a->vm, a->rd) && \ 2998 (a->rd != a->rs2) && \ 2999 (s->vstart == 0)) { \ 3000 uint32_t data = 0; \ 3001 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 3002 TCGLabel *over = gen_new_label(); \ 3003 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 3004 \ 3005 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3006 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3007 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 3008 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 3009 cpu_env, s->vlen / 8, s->vlen / 8, \ 3010 data, fn); \ 3011 mark_vs_dirty(s); \ 3012 gen_set_label(over); \ 3013 return true; \ 3014 } \ 3015 return false; \ 3016} 3017 3018GEN_M_TRANS(vmsbf_m) 3019GEN_M_TRANS(vmsif_m) 3020GEN_M_TRANS(vmsof_m) 3021 3022/* 3023 * Vector Iota Instruction 3024 * 3025 * 1. The destination register cannot overlap the source register. 3026 * 2. If masked, cannot overlap the mask register ('v0'). 3027 * 3. An illegal instruction exception is raised if vstart is non-zero. 3028 */ 3029static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 3030{ 3031 if (require_rvv(s) && 3032 vext_check_isa_ill(s) && 3033 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 3034 require_vm(a->vm, a->rd) && 3035 require_align(a->rd, s->lmul) && 3036 (s->vstart == 0)) { 3037 uint32_t data = 0; 3038 TCGLabel *over = gen_new_label(); 3039 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3040 3041 data = FIELD_DP32(data, VDATA, VM, a->vm); 3042 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3043 static gen_helper_gvec_3_ptr * const fns[4] = { 3044 gen_helper_viota_m_b, gen_helper_viota_m_h, 3045 gen_helper_viota_m_w, gen_helper_viota_m_d, 3046 }; 3047 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3048 vreg_ofs(s, a->rs2), cpu_env, 3049 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 3050 mark_vs_dirty(s); 3051 gen_set_label(over); 3052 return true; 3053 } 3054 return false; 3055} 3056 3057/* Vector Element Index Instruction */ 3058static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3059{ 3060 if (require_rvv(s) && 3061 vext_check_isa_ill(s) && 3062 require_align(a->rd, s->lmul) && 3063 require_vm(a->vm, a->rd)) { 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_2_ptr * const fns[4] = { 3071 gen_helper_vid_v_b, gen_helper_vid_v_h, 3072 gen_helper_vid_v_w, gen_helper_vid_v_d, 3073 }; 3074 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3075 cpu_env, s->vlen / 8, s->vlen / 8, 3076 data, fns[s->sew]); 3077 mark_vs_dirty(s); 3078 gen_set_label(over); 3079 return true; 3080 } 3081 return false; 3082} 3083 3084/* 3085 *** Vector Permutation Instructions 3086 */ 3087 3088static void load_element(TCGv_i64 dest, TCGv_ptr base, 3089 int ofs, int sew, bool sign) 3090{ 3091 switch (sew) { 3092 case MO_8: 3093 if (!sign) { 3094 tcg_gen_ld8u_i64(dest, base, ofs); 3095 } else { 3096 tcg_gen_ld8s_i64(dest, base, ofs); 3097 } 3098 break; 3099 case MO_16: 3100 if (!sign) { 3101 tcg_gen_ld16u_i64(dest, base, ofs); 3102 } else { 3103 tcg_gen_ld16s_i64(dest, base, ofs); 3104 } 3105 break; 3106 case MO_32: 3107 if (!sign) { 3108 tcg_gen_ld32u_i64(dest, base, ofs); 3109 } else { 3110 tcg_gen_ld32s_i64(dest, base, ofs); 3111 } 3112 break; 3113 case MO_64: 3114 tcg_gen_ld_i64(dest, base, ofs); 3115 break; 3116 default: 3117 g_assert_not_reached(); 3118 break; 3119 } 3120} 3121 3122/* offset of the idx element with base regsiter r */ 3123static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3124{ 3125#ifdef HOST_WORDS_BIGENDIAN 3126 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3127#else 3128 return vreg_ofs(s, r) + (idx << s->sew); 3129#endif 3130} 3131 3132/* adjust the index according to the endian */ 3133static void endian_adjust(TCGv_i32 ofs, int sew) 3134{ 3135#ifdef HOST_WORDS_BIGENDIAN 3136 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3137#endif 3138} 3139 3140/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3141static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3142 int vreg, TCGv idx, int vlmax) 3143{ 3144 TCGv_i32 ofs = tcg_temp_new_i32(); 3145 TCGv_ptr base = tcg_temp_new_ptr(); 3146 TCGv_i64 t_idx = tcg_temp_new_i64(); 3147 TCGv_i64 t_vlmax, t_zero; 3148 3149 /* 3150 * Mask the index to the length so that we do 3151 * not produce an out-of-range load. 3152 */ 3153 tcg_gen_trunc_tl_i32(ofs, idx); 3154 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3155 3156 /* Convert the index to an offset. */ 3157 endian_adjust(ofs, s->sew); 3158 tcg_gen_shli_i32(ofs, ofs, s->sew); 3159 3160 /* Convert the index to a pointer. */ 3161 tcg_gen_ext_i32_ptr(base, ofs); 3162 tcg_gen_add_ptr(base, base, cpu_env); 3163 3164 /* Perform the load. */ 3165 load_element(dest, base, 3166 vreg_ofs(s, vreg), s->sew, false); 3167 tcg_temp_free_ptr(base); 3168 tcg_temp_free_i32(ofs); 3169 3170 /* Flush out-of-range indexing to zero. */ 3171 t_vlmax = tcg_constant_i64(vlmax); 3172 t_zero = tcg_constant_i64(0); 3173 tcg_gen_extu_tl_i64(t_idx, idx); 3174 3175 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3176 t_vlmax, dest, t_zero); 3177 3178 tcg_temp_free_i64(t_idx); 3179} 3180 3181static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3182 int vreg, int idx, bool sign) 3183{ 3184 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign); 3185} 3186 3187/* Integer Scalar Move Instruction */ 3188 3189static void store_element(TCGv_i64 val, TCGv_ptr base, 3190 int ofs, int sew) 3191{ 3192 switch (sew) { 3193 case MO_8: 3194 tcg_gen_st8_i64(val, base, ofs); 3195 break; 3196 case MO_16: 3197 tcg_gen_st16_i64(val, base, ofs); 3198 break; 3199 case MO_32: 3200 tcg_gen_st32_i64(val, base, ofs); 3201 break; 3202 case MO_64: 3203 tcg_gen_st_i64(val, base, ofs); 3204 break; 3205 default: 3206 g_assert_not_reached(); 3207 break; 3208 } 3209} 3210 3211/* 3212 * Store vreg[idx] = val. 3213 * The index must be in range of VLMAX. 3214 */ 3215static void vec_element_storei(DisasContext *s, int vreg, 3216 int idx, TCGv_i64 val) 3217{ 3218 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 3219} 3220 3221/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3222static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3223{ 3224 if (require_rvv(s) && 3225 vext_check_isa_ill(s)) { 3226 TCGv_i64 t1; 3227 TCGv dest; 3228 3229 t1 = tcg_temp_new_i64(); 3230 dest = tcg_temp_new(); 3231 /* 3232 * load vreg and sign-extend to 64 bits, 3233 * then truncate to XLEN bits before storing to gpr. 3234 */ 3235 vec_element_loadi(s, t1, a->rs2, 0, true); 3236 tcg_gen_trunc_i64_tl(dest, t1); 3237 gen_set_gpr(s, a->rd, dest); 3238 tcg_temp_free_i64(t1); 3239 tcg_temp_free(dest); 3240 3241 return true; 3242 } 3243 return false; 3244} 3245 3246/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3247static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3248{ 3249 if (require_rvv(s) && 3250 vext_check_isa_ill(s)) { 3251 /* This instruction ignores LMUL and vector register groups */ 3252 TCGv_i64 t1; 3253 TCGv s1; 3254 TCGLabel *over = gen_new_label(); 3255 3256 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3257 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3258 3259 t1 = tcg_temp_new_i64(); 3260 3261 /* 3262 * load gpr and sign-extend to 64 bits, 3263 * then truncate to SEW bits when storing to vreg. 3264 */ 3265 s1 = get_gpr(s, a->rs1, EXT_NONE); 3266 tcg_gen_ext_tl_i64(t1, s1); 3267 vec_element_storei(s, a->rd, 0, t1); 3268 tcg_temp_free_i64(t1); 3269 mark_vs_dirty(s); 3270 gen_set_label(over); 3271 return true; 3272 } 3273 return false; 3274} 3275 3276/* Floating-Point Scalar Move Instructions */ 3277static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3278{ 3279 if (require_rvv(s) && 3280 require_rvf(s) && 3281 vext_check_isa_ill(s)) { 3282 gen_set_rm(s, RISCV_FRM_DYN); 3283 3284 unsigned int ofs = (8 << s->sew); 3285 unsigned int len = 64 - ofs; 3286 TCGv_i64 t_nan; 3287 3288 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3289 /* NaN-box f[rd] as necessary for SEW */ 3290 if (len) { 3291 t_nan = tcg_constant_i64(UINT64_MAX); 3292 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3293 t_nan, ofs, len); 3294 } 3295 3296 mark_fs_dirty(s); 3297 return true; 3298 } 3299 return false; 3300} 3301 3302/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3303static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3304{ 3305 if (require_rvv(s) && 3306 require_rvf(s) && 3307 vext_check_isa_ill(s)) { 3308 gen_set_rm(s, RISCV_FRM_DYN); 3309 3310 /* The instructions ignore LMUL and vector register group. */ 3311 TCGv_i64 t1; 3312 TCGLabel *over = gen_new_label(); 3313 3314 /* if vl == 0 or vstart >= vl, skip vector register write back */ 3315 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3316 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3317 3318 /* NaN-box f[rs1] */ 3319 t1 = tcg_temp_new_i64(); 3320 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3321 3322 vec_element_storei(s, a->rd, 0, t1); 3323 tcg_temp_free_i64(t1); 3324 mark_vs_dirty(s); 3325 gen_set_label(over); 3326 return true; 3327 } 3328 return false; 3329} 3330 3331/* Vector Slide Instructions */ 3332static bool slideup_check(DisasContext *s, arg_rmrr *a) 3333{ 3334 return require_rvv(s) && 3335 vext_check_isa_ill(s) && 3336 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3337} 3338 3339GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3340GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3341GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3342 3343static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3344{ 3345 return require_rvv(s) && 3346 vext_check_isa_ill(s) && 3347 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3348} 3349 3350GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3351GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3352GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3353 3354/* Vector Floating-Point Slide Instructions */ 3355static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3356{ 3357 return slideup_check(s, a) && 3358 require_rvf(s); 3359} 3360 3361static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3362{ 3363 return slidedown_check(s, a) && 3364 require_rvf(s); 3365} 3366 3367GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3368GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3369 3370/* Vector Register Gather Instruction */ 3371static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3372{ 3373 return require_rvv(s) && 3374 vext_check_isa_ill(s) && 3375 require_align(a->rd, s->lmul) && 3376 require_align(a->rs1, s->lmul) && 3377 require_align(a->rs2, s->lmul) && 3378 (a->rd != a->rs2 && a->rd != a->rs1) && 3379 require_vm(a->vm, a->rd); 3380} 3381 3382static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3383{ 3384 int8_t emul = MO_16 - s->sew + s->lmul; 3385 return require_rvv(s) && 3386 vext_check_isa_ill(s) && 3387 (emul >= -3 && emul <= 3) && 3388 require_align(a->rd, s->lmul) && 3389 require_align(a->rs1, emul) && 3390 require_align(a->rs2, s->lmul) && 3391 (a->rd != a->rs2 && a->rd != a->rs1) && 3392 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3393 a->rs1, 1 << MAX(emul, 0)) && 3394 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3395 a->rs2, 1 << MAX(s->lmul, 0)) && 3396 require_vm(a->vm, a->rd); 3397} 3398 3399GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3400GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3401 3402static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3403{ 3404 return require_rvv(s) && 3405 vext_check_isa_ill(s) && 3406 require_align(a->rd, s->lmul) && 3407 require_align(a->rs2, s->lmul) && 3408 (a->rd != a->rs2) && 3409 require_vm(a->vm, a->rd); 3410} 3411 3412/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3413static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3414{ 3415 if (!vrgather_vx_check(s, a)) { 3416 return false; 3417 } 3418 3419 if (a->vm && s->vl_eq_vlmax) { 3420 int scale = s->lmul - (s->sew + 3); 3421 int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale; 3422 TCGv_i64 dest = tcg_temp_new_i64(); 3423 3424 if (a->rs1 == 0) { 3425 vec_element_loadi(s, dest, a->rs2, 0, false); 3426 } else { 3427 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3428 } 3429 3430 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3431 MAXSZ(s), MAXSZ(s), dest); 3432 tcg_temp_free_i64(dest); 3433 mark_vs_dirty(s); 3434 } else { 3435 static gen_helper_opivx * const fns[4] = { 3436 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3437 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3438 }; 3439 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3440 } 3441 return true; 3442} 3443 3444/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3445static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3446{ 3447 if (!vrgather_vx_check(s, a)) { 3448 return false; 3449 } 3450 3451 if (a->vm && s->vl_eq_vlmax) { 3452 int scale = s->lmul - (s->sew + 3); 3453 int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale; 3454 if (a->rs1 >= vlmax) { 3455 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3456 MAXSZ(s), MAXSZ(s), 0); 3457 } else { 3458 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3459 endian_ofs(s, a->rs2, a->rs1), 3460 MAXSZ(s), MAXSZ(s)); 3461 } 3462 mark_vs_dirty(s); 3463 } else { 3464 static gen_helper_opivx * const fns[4] = { 3465 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3466 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3467 }; 3468 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3469 s, IMM_ZX); 3470 } 3471 return true; 3472} 3473 3474/* 3475 * Vector Compress Instruction 3476 * 3477 * The destination vector register group cannot overlap the 3478 * source vector register group or the source mask register. 3479 */ 3480static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3481{ 3482 return require_rvv(s) && 3483 vext_check_isa_ill(s) && 3484 require_align(a->rd, s->lmul) && 3485 require_align(a->rs2, s->lmul) && 3486 (a->rd != a->rs2) && 3487 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3488 (s->vstart == 0); 3489} 3490 3491static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3492{ 3493 if (vcompress_vm_check(s, a)) { 3494 uint32_t data = 0; 3495 static gen_helper_gvec_4_ptr * const fns[4] = { 3496 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3497 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3498 }; 3499 TCGLabel *over = gen_new_label(); 3500 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3501 3502 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3503 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3504 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3505 cpu_env, s->vlen / 8, s->vlen / 8, data, 3506 fns[s->sew]); 3507 mark_vs_dirty(s); 3508 gen_set_label(over); 3509 return true; 3510 } 3511 return false; 3512} 3513 3514/* 3515 * Whole Vector Register Move Instructions ignore vtype and vl setting. 3516 * Thus, we don't need to check vill bit. (Section 16.6) 3517 */ 3518#define GEN_VMV_WHOLE_TRANS(NAME, LEN, SEQ) \ 3519static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3520{ \ 3521 if (require_rvv(s) && \ 3522 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3523 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3524 uint32_t maxsz = (s->vlen >> 3) * LEN; \ 3525 if (s->vstart == 0) { \ 3526 /* EEW = 8 */ \ 3527 tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd), \ 3528 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3529 mark_vs_dirty(s); \ 3530 } else { \ 3531 TCGLabel *over = gen_new_label(); \ 3532 tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ 3533 \ 3534 static gen_helper_gvec_2_ptr * const fns[4] = { \ 3535 gen_helper_vmv1r_v, gen_helper_vmv2r_v, \ 3536 gen_helper_vmv4r_v, gen_helper_vmv8r_v, \ 3537 }; \ 3538 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3539 cpu_env, maxsz, maxsz, 0, fns[SEQ]); \ 3540 mark_vs_dirty(s); \ 3541 gen_set_label(over); \ 3542 } \ 3543 return true; \ 3544 } \ 3545 return false; \ 3546} 3547 3548GEN_VMV_WHOLE_TRANS(vmv1r_v, 1, 0) 3549GEN_VMV_WHOLE_TRANS(vmv2r_v, 2, 1) 3550GEN_VMV_WHOLE_TRANS(vmv4r_v, 4, 2) 3551GEN_VMV_WHOLE_TRANS(vmv8r_v, 8, 3) 3552 3553static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3554{ 3555 uint8_t from = (s->sew + 3) - div; 3556 bool ret = require_rvv(s) && 3557 (from >= 3 && from <= 8) && 3558 (a->rd != a->rs2) && 3559 require_align(a->rd, s->lmul) && 3560 require_align(a->rs2, s->lmul - div) && 3561 require_vm(a->vm, a->rd) && 3562 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3563 return ret; 3564} 3565 3566static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3567{ 3568 uint32_t data = 0; 3569 gen_helper_gvec_3_ptr *fn; 3570 TCGLabel *over = gen_new_label(); 3571 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3572 3573 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3574 { 3575 NULL, gen_helper_vzext_vf2_h, 3576 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3577 }, 3578 { 3579 NULL, NULL, 3580 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3581 }, 3582 { 3583 NULL, NULL, 3584 NULL, gen_helper_vzext_vf8_d 3585 }, 3586 { 3587 NULL, gen_helper_vsext_vf2_h, 3588 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3589 }, 3590 { 3591 NULL, NULL, 3592 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3593 }, 3594 { 3595 NULL, NULL, 3596 NULL, gen_helper_vsext_vf8_d 3597 } 3598 }; 3599 3600 fn = fns[seq][s->sew]; 3601 if (fn == NULL) { 3602 return false; 3603 } 3604 3605 data = FIELD_DP32(data, VDATA, VM, a->vm); 3606 3607 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3608 vreg_ofs(s, a->rs2), cpu_env, 3609 s->vlen / 8, s->vlen / 8, data, fn); 3610 3611 mark_vs_dirty(s); 3612 gen_set_label(over); 3613 return true; 3614} 3615 3616/* Vector Integer Extension */ 3617#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3618static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3619{ \ 3620 if (int_ext_check(s, a, DIV)) { \ 3621 return int_ext_op(s, a, SEQ); \ 3622 } \ 3623 return false; \ 3624} 3625 3626GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3627GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3628GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3629GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3630GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3631GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3632