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