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