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