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_scale_rvf(s) && 2258 (s->sew != MO_8) && 2259 vext_check_isa_ill(s) && 2260 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2261} 2262 2263/* OPFVV with WIDEN */ 2264#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2265static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2266{ \ 2267 if (CHECK(s, a)) { \ 2268 uint32_t data = 0; \ 2269 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2270 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2271 }; \ 2272 TCGLabel *over = gen_new_label(); \ 2273 gen_set_rm(s, RISCV_FRM_DYN); \ 2274 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2275 \ 2276 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2277 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2278 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2279 vreg_ofs(s, a->rs1), \ 2280 vreg_ofs(s, a->rs2), cpu_env, \ 2281 s->vlen / 8, s->vlen / 8, data, \ 2282 fns[s->sew - 1]); \ 2283 mark_vs_dirty(s); \ 2284 gen_set_label(over); \ 2285 return true; \ 2286 } \ 2287 return false; \ 2288} 2289 2290GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2291GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2292 2293static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2294{ 2295 return require_rvv(s) && 2296 require_scale_rvf(s) && 2297 (s->sew != MO_8) && 2298 vext_check_isa_ill(s) && 2299 vext_check_ds(s, a->rd, a->rs2, a->vm); 2300} 2301 2302/* OPFVF with WIDEN */ 2303#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2304static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2305{ \ 2306 if (opfvf_widen_check(s, a)) { \ 2307 uint32_t data = 0; \ 2308 static gen_helper_opfvf *const fns[2] = { \ 2309 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2310 }; \ 2311 gen_set_rm(s, RISCV_FRM_DYN); \ 2312 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2313 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2314 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2315 fns[s->sew - 1], s); \ 2316 } \ 2317 return false; \ 2318} 2319 2320GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2321GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2322 2323static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2324{ 2325 return require_rvv(s) && 2326 require_scale_rvf(s) && 2327 (s->sew != MO_8) && 2328 vext_check_isa_ill(s) && 2329 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2330} 2331 2332/* WIDEN OPFVV with WIDEN */ 2333#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2334static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2335{ \ 2336 if (opfwv_widen_check(s, a)) { \ 2337 uint32_t data = 0; \ 2338 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2339 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2340 }; \ 2341 TCGLabel *over = gen_new_label(); \ 2342 gen_set_rm(s, RISCV_FRM_DYN); \ 2343 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2344 \ 2345 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2346 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2347 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2348 vreg_ofs(s, a->rs1), \ 2349 vreg_ofs(s, a->rs2), cpu_env, \ 2350 s->vlen / 8, s->vlen / 8, data, \ 2351 fns[s->sew - 1]); \ 2352 mark_vs_dirty(s); \ 2353 gen_set_label(over); \ 2354 return true; \ 2355 } \ 2356 return false; \ 2357} 2358 2359GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2360GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2361 2362static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2363{ 2364 return require_rvv(s) && 2365 require_scale_rvf(s) && 2366 (s->sew != MO_8) && 2367 vext_check_isa_ill(s) && 2368 vext_check_dd(s, a->rd, a->rs2, a->vm); 2369} 2370 2371/* WIDEN OPFVF with WIDEN */ 2372#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2373static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2374{ \ 2375 if (opfwf_widen_check(s, a)) { \ 2376 uint32_t data = 0; \ 2377 static gen_helper_opfvf *const fns[2] = { \ 2378 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2379 }; \ 2380 gen_set_rm(s, RISCV_FRM_DYN); \ 2381 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2382 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2383 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2384 fns[s->sew - 1], s); \ 2385 } \ 2386 return false; \ 2387} 2388 2389GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2390GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2391 2392/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2393GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2394GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2395GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2396GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2397GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2398 2399/* Vector Widening Floating-Point Multiply */ 2400GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2401GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2402 2403/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2404GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2405GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2406GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2407GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2408GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2409GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2410GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2411GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2412GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2413GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2414GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2415GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2416GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2417GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2418GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2419GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2420 2421/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2422GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2423GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2424GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2425GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2426GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2427GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2428GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2429GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2430 2431/* Vector Floating-Point Square-Root Instruction */ 2432 2433/* 2434 * If the current SEW does not correspond to a supported IEEE floating-point 2435 * type, an illegal instruction exception is raised 2436 */ 2437static bool opfv_check(DisasContext *s, arg_rmr *a) 2438{ 2439 return require_rvv(s) && 2440 require_rvf(s) && 2441 vext_check_isa_ill(s) && 2442 /* OPFV instructions ignore vs1 check */ 2443 vext_check_ss(s, a->rd, a->rs2, a->vm); 2444} 2445 2446static bool do_opfv(DisasContext *s, arg_rmr *a, 2447 gen_helper_gvec_3_ptr *fn, 2448 bool (*checkfn)(DisasContext *, arg_rmr *), 2449 int rm) 2450{ 2451 if (checkfn(s, a)) { 2452 if (rm != RISCV_FRM_DYN) { 2453 gen_set_rm(s, RISCV_FRM_DYN); 2454 } 2455 2456 uint32_t data = 0; 2457 TCGLabel *over = gen_new_label(); 2458 gen_set_rm(s, rm); 2459 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2460 2461 data = FIELD_DP32(data, VDATA, VM, a->vm); 2462 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2463 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2464 vreg_ofs(s, a->rs2), cpu_env, 2465 s->vlen / 8, s->vlen / 8, data, fn); 2466 mark_vs_dirty(s); 2467 gen_set_label(over); 2468 return true; 2469 } 2470 return false; 2471} 2472 2473#define GEN_OPFV_TRANS(NAME, CHECK, FRM) \ 2474static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2475{ \ 2476 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2477 gen_helper_##NAME##_h, \ 2478 gen_helper_##NAME##_w, \ 2479 gen_helper_##NAME##_d \ 2480 }; \ 2481 return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \ 2482} 2483 2484GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN) 2485GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN) 2486GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN) 2487 2488/* Vector Floating-Point MIN/MAX Instructions */ 2489GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2490GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2491GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2492GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2493 2494/* Vector Floating-Point Sign-Injection Instructions */ 2495GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2496GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2497GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2498GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2499GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2500GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2501 2502/* Vector Floating-Point Compare Instructions */ 2503static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2504{ 2505 return require_rvv(s) && 2506 require_rvf(s) && 2507 vext_check_isa_ill(s) && 2508 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2509} 2510 2511GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2512GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2513GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2514GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2515 2516static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2517{ 2518 return require_rvv(s) && 2519 require_rvf(s) && 2520 vext_check_isa_ill(s) && 2521 vext_check_ms(s, a->rd, a->rs2); 2522} 2523 2524GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2525GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2526GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2527GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2528GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2529GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2530 2531/* Vector Floating-Point Classify Instruction */ 2532GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN) 2533 2534/* Vector Floating-Point Merge Instruction */ 2535GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2536 2537static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2538{ 2539 if (require_rvv(s) && 2540 require_rvf(s) && 2541 vext_check_isa_ill(s) && 2542 require_align(a->rd, s->lmul)) { 2543 gen_set_rm(s, RISCV_FRM_DYN); 2544 2545 TCGv_i64 t1; 2546 2547 if (s->vl_eq_vlmax) { 2548 t1 = tcg_temp_new_i64(); 2549 /* NaN-box f[rs1] */ 2550 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2551 2552 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2553 MAXSZ(s), MAXSZ(s), t1); 2554 mark_vs_dirty(s); 2555 } else { 2556 TCGv_ptr dest; 2557 TCGv_i32 desc; 2558 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2559 static gen_helper_vmv_vx * const fns[3] = { 2560 gen_helper_vmv_v_x_h, 2561 gen_helper_vmv_v_x_w, 2562 gen_helper_vmv_v_x_d, 2563 }; 2564 TCGLabel *over = gen_new_label(); 2565 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2566 2567 t1 = tcg_temp_new_i64(); 2568 /* NaN-box f[rs1] */ 2569 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2570 2571 dest = tcg_temp_new_ptr(); 2572 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2573 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2574 2575 fns[s->sew - 1](dest, t1, cpu_env, desc); 2576 2577 tcg_temp_free_ptr(dest); 2578 mark_vs_dirty(s); 2579 gen_set_label(over); 2580 } 2581 tcg_temp_free_i64(t1); 2582 return true; 2583 } 2584 return false; 2585} 2586 2587/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2588#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM) \ 2589static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2590{ \ 2591 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2592 gen_helper_##HELPER##_h, \ 2593 gen_helper_##HELPER##_w, \ 2594 gen_helper_##HELPER##_d \ 2595 }; \ 2596 return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \ 2597} 2598 2599GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN) 2600GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN) 2601GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN) 2602GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN) 2603/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */ 2604GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ) 2605GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ) 2606 2607/* Widening Floating-Point/Integer Type-Convert Instructions */ 2608 2609/* 2610 * If the current SEW does not correspond to a supported IEEE floating-point 2611 * type, an illegal instruction exception is raised 2612 */ 2613static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2614{ 2615 return require_rvv(s) && 2616 require_scale_rvf(s) && 2617 (s->sew != MO_8) && 2618 vext_check_isa_ill(s) && 2619 vext_check_ds(s, a->rd, a->rs2, a->vm); 2620} 2621 2622#define GEN_OPFV_WIDEN_TRANS(NAME, HELPER, FRM) \ 2623static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2624{ \ 2625 if (opfv_widen_check(s, a)) { \ 2626 if (FRM != RISCV_FRM_DYN) { \ 2627 gen_set_rm(s, RISCV_FRM_DYN); \ 2628 } \ 2629 \ 2630 uint32_t data = 0; \ 2631 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2632 gen_helper_##HELPER##_h, \ 2633 gen_helper_##HELPER##_w, \ 2634 }; \ 2635 TCGLabel *over = gen_new_label(); \ 2636 gen_set_rm(s, FRM); \ 2637 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2638 \ 2639 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2640 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2641 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2642 vreg_ofs(s, a->rs2), cpu_env, \ 2643 s->vlen / 8, s->vlen / 8, data, \ 2644 fns[s->sew - 1]); \ 2645 mark_vs_dirty(s); \ 2646 gen_set_label(over); \ 2647 return true; \ 2648 } \ 2649 return false; \ 2650} 2651 2652GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, vfwcvt_xu_f_v, RISCV_FRM_DYN) 2653GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, vfwcvt_x_f_v, RISCV_FRM_DYN) 2654GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, vfwcvt_f_f_v, RISCV_FRM_DYN) 2655/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2656GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, vfwcvt_xu_f_v, RISCV_FRM_RTZ) 2657GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, vfwcvt_x_f_v, RISCV_FRM_RTZ) 2658 2659static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2660{ 2661 return require_rvv(s) && 2662 require_scale_rvf(s) && 2663 vext_check_isa_ill(s) && 2664 /* OPFV widening instructions ignore vs1 check */ 2665 vext_check_ds(s, a->rd, a->rs2, a->vm); 2666} 2667 2668#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2669static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2670{ \ 2671 if (opfxv_widen_check(s, a)) { \ 2672 uint32_t data = 0; \ 2673 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2674 gen_helper_##NAME##_b, \ 2675 gen_helper_##NAME##_h, \ 2676 gen_helper_##NAME##_w, \ 2677 }; \ 2678 TCGLabel *over = gen_new_label(); \ 2679 gen_set_rm(s, RISCV_FRM_DYN); \ 2680 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2681 \ 2682 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2683 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2684 vreg_ofs(s, a->rs2), cpu_env, \ 2685 s->vlen / 8, s->vlen / 8, data, \ 2686 fns[s->sew]); \ 2687 mark_vs_dirty(s); \ 2688 gen_set_label(over); \ 2689 return true; \ 2690 } \ 2691 return false; \ 2692} 2693 2694GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 2695GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 2696 2697/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2698 2699/* 2700 * If the current SEW does not correspond to a supported IEEE floating-point 2701 * type, an illegal instruction exception is raised 2702 */ 2703static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2704{ 2705 return require_rvv(s) && 2706 require_rvf(s) && 2707 (s->sew != MO_64) && 2708 vext_check_isa_ill(s) && 2709 /* OPFV narrowing instructions ignore vs1 check */ 2710 vext_check_sd(s, a->rd, a->rs2, a->vm); 2711} 2712 2713#define GEN_OPFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2714static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2715{ \ 2716 if (opfv_narrow_check(s, a)) { \ 2717 if (FRM != RISCV_FRM_DYN) { \ 2718 gen_set_rm(s, RISCV_FRM_DYN); \ 2719 } \ 2720 \ 2721 uint32_t data = 0; \ 2722 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2723 gen_helper_##HELPER##_h, \ 2724 gen_helper_##HELPER##_w, \ 2725 }; \ 2726 TCGLabel *over = gen_new_label(); \ 2727 gen_set_rm(s, FRM); \ 2728 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2729 \ 2730 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2731 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2732 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2733 vreg_ofs(s, a->rs2), cpu_env, \ 2734 s->vlen / 8, s->vlen / 8, data, \ 2735 fns[s->sew - 1]); \ 2736 mark_vs_dirty(s); \ 2737 gen_set_label(over); \ 2738 return true; \ 2739 } \ 2740 return false; \ 2741} 2742 2743GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, vfncvt_f_xu_w, RISCV_FRM_DYN) 2744GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, vfncvt_f_x_w, RISCV_FRM_DYN) 2745GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, vfncvt_f_f_w, RISCV_FRM_DYN) 2746/* Reuse the helper function from vfncvt.f.f.w */ 2747GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, vfncvt_f_f_w, RISCV_FRM_ROD) 2748 2749static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 2750{ 2751 return require_rvv(s) && 2752 require_scale_rvf(s) && 2753 vext_check_isa_ill(s) && 2754 /* OPFV narrowing instructions ignore vs1 check */ 2755 vext_check_sd(s, a->rd, a->rs2, a->vm); 2756} 2757 2758#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2759static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2760{ \ 2761 if (opxfv_narrow_check(s, a)) { \ 2762 if (FRM != RISCV_FRM_DYN) { \ 2763 gen_set_rm(s, RISCV_FRM_DYN); \ 2764 } \ 2765 \ 2766 uint32_t data = 0; \ 2767 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2768 gen_helper_##HELPER##_b, \ 2769 gen_helper_##HELPER##_h, \ 2770 gen_helper_##HELPER##_w, \ 2771 }; \ 2772 TCGLabel *over = gen_new_label(); \ 2773 gen_set_rm(s, FRM); \ 2774 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2775 \ 2776 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2777 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2778 vreg_ofs(s, a->rs2), cpu_env, \ 2779 s->vlen / 8, s->vlen / 8, data, \ 2780 fns[s->sew]); \ 2781 mark_vs_dirty(s); \ 2782 gen_set_label(over); \ 2783 return true; \ 2784 } \ 2785 return false; \ 2786} 2787 2788GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 2789GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 2790/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 2791GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 2792GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 2793 2794/* 2795 *** Vector Reduction Operations 2796 */ 2797/* Vector Single-Width Integer Reduction Instructions */ 2798static bool reduction_check(DisasContext *s, arg_rmrr *a) 2799{ 2800 return require_rvv(s) && 2801 vext_check_isa_ill(s) && 2802 vext_check_reduction(s, a->rs2); 2803} 2804 2805GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2806GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2807GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2808GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2809GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2810GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2811GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2812GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2813 2814/* Vector Widening Integer Reduction Instructions */ 2815static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2816{ 2817 return reduction_check(s, a) && (s->sew < MO_64) && 2818 ((s->sew + 1) <= (s->elen >> 4)); 2819} 2820 2821GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2822GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2823 2824/* Vector Single-Width Floating-Point Reduction Instructions */ 2825static bool freduction_check(DisasContext *s, arg_rmrr *a) 2826{ 2827 return reduction_check(s, a) && 2828 require_rvf(s); 2829} 2830 2831GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) 2832GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 2833GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 2834 2835/* Vector Widening Floating-Point Reduction Instructions */ 2836static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 2837{ 2838 return reduction_widen_check(s, a) && 2839 require_scale_rvf(s) && 2840 (s->sew != MO_8); 2841} 2842 2843GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check) 2844 2845/* 2846 *** Vector Mask Operations 2847 */ 2848 2849/* Vector Mask-Register Logical Instructions */ 2850#define GEN_MM_TRANS(NAME) \ 2851static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2852{ \ 2853 if (require_rvv(s) && \ 2854 vext_check_isa_ill(s)) { \ 2855 uint32_t data = 0; \ 2856 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2857 TCGLabel *over = gen_new_label(); \ 2858 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2859 \ 2860 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2861 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2862 vreg_ofs(s, a->rs1), \ 2863 vreg_ofs(s, a->rs2), cpu_env, \ 2864 s->vlen / 8, s->vlen / 8, data, fn); \ 2865 mark_vs_dirty(s); \ 2866 gen_set_label(over); \ 2867 return true; \ 2868 } \ 2869 return false; \ 2870} 2871 2872GEN_MM_TRANS(vmand_mm) 2873GEN_MM_TRANS(vmnand_mm) 2874GEN_MM_TRANS(vmandn_mm) 2875GEN_MM_TRANS(vmxor_mm) 2876GEN_MM_TRANS(vmor_mm) 2877GEN_MM_TRANS(vmnor_mm) 2878GEN_MM_TRANS(vmorn_mm) 2879GEN_MM_TRANS(vmxnor_mm) 2880 2881/* Vector count population in mask vcpop */ 2882static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 2883{ 2884 if (require_rvv(s) && 2885 vext_check_isa_ill(s) && 2886 s->vstart == 0) { 2887 TCGv_ptr src2, mask; 2888 TCGv dst; 2889 TCGv_i32 desc; 2890 uint32_t data = 0; 2891 data = FIELD_DP32(data, VDATA, VM, a->vm); 2892 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2893 2894 mask = tcg_temp_new_ptr(); 2895 src2 = tcg_temp_new_ptr(); 2896 dst = dest_gpr(s, a->rd); 2897 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2898 2899 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2900 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2901 2902 gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc); 2903 gen_set_gpr(s, a->rd, dst); 2904 2905 tcg_temp_free_ptr(mask); 2906 tcg_temp_free_ptr(src2); 2907 2908 return true; 2909 } 2910 return false; 2911} 2912 2913/* vmfirst find-first-set mask bit */ 2914static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 2915{ 2916 if (require_rvv(s) && 2917 vext_check_isa_ill(s) && 2918 s->vstart == 0) { 2919 TCGv_ptr src2, mask; 2920 TCGv dst; 2921 TCGv_i32 desc; 2922 uint32_t data = 0; 2923 data = FIELD_DP32(data, VDATA, VM, a->vm); 2924 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2925 2926 mask = tcg_temp_new_ptr(); 2927 src2 = tcg_temp_new_ptr(); 2928 dst = dest_gpr(s, a->rd); 2929 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2930 2931 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2932 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2933 2934 gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); 2935 gen_set_gpr(s, a->rd, dst); 2936 2937 tcg_temp_free_ptr(mask); 2938 tcg_temp_free_ptr(src2); 2939 return true; 2940 } 2941 return false; 2942} 2943 2944/* vmsbf.m set-before-first mask bit */ 2945/* vmsif.m set-includ-first mask bit */ 2946/* vmsof.m set-only-first mask bit */ 2947#define GEN_M_TRANS(NAME) \ 2948static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2949{ \ 2950 if (require_rvv(s) && \ 2951 vext_check_isa_ill(s) && \ 2952 require_vm(a->vm, a->rd) && \ 2953 (a->rd != a->rs2) && \ 2954 (s->vstart == 0)) { \ 2955 uint32_t data = 0; \ 2956 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2957 TCGLabel *over = gen_new_label(); \ 2958 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2959 \ 2960 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2961 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2962 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2963 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2964 cpu_env, s->vlen / 8, s->vlen / 8, \ 2965 data, fn); \ 2966 mark_vs_dirty(s); \ 2967 gen_set_label(over); \ 2968 return true; \ 2969 } \ 2970 return false; \ 2971} 2972 2973GEN_M_TRANS(vmsbf_m) 2974GEN_M_TRANS(vmsif_m) 2975GEN_M_TRANS(vmsof_m) 2976 2977/* 2978 * Vector Iota Instruction 2979 * 2980 * 1. The destination register cannot overlap the source register. 2981 * 2. If masked, cannot overlap the mask register ('v0'). 2982 * 3. An illegal instruction exception is raised if vstart is non-zero. 2983 */ 2984static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2985{ 2986 if (require_rvv(s) && 2987 vext_check_isa_ill(s) && 2988 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 2989 require_vm(a->vm, a->rd) && 2990 require_align(a->rd, s->lmul) && 2991 (s->vstart == 0)) { 2992 uint32_t data = 0; 2993 TCGLabel *over = gen_new_label(); 2994 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2995 2996 data = FIELD_DP32(data, VDATA, VM, a->vm); 2997 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2998 static gen_helper_gvec_3_ptr * const fns[4] = { 2999 gen_helper_viota_m_b, gen_helper_viota_m_h, 3000 gen_helper_viota_m_w, gen_helper_viota_m_d, 3001 }; 3002 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3003 vreg_ofs(s, a->rs2), cpu_env, 3004 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 3005 mark_vs_dirty(s); 3006 gen_set_label(over); 3007 return true; 3008 } 3009 return false; 3010} 3011 3012/* Vector Element Index Instruction */ 3013static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3014{ 3015 if (require_rvv(s) && 3016 vext_check_isa_ill(s) && 3017 require_align(a->rd, s->lmul) && 3018 require_vm(a->vm, a->rd)) { 3019 uint32_t data = 0; 3020 TCGLabel *over = gen_new_label(); 3021 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3022 3023 data = FIELD_DP32(data, VDATA, VM, a->vm); 3024 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3025 static gen_helper_gvec_2_ptr * const fns[4] = { 3026 gen_helper_vid_v_b, gen_helper_vid_v_h, 3027 gen_helper_vid_v_w, gen_helper_vid_v_d, 3028 }; 3029 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3030 cpu_env, s->vlen / 8, s->vlen / 8, 3031 data, fns[s->sew]); 3032 mark_vs_dirty(s); 3033 gen_set_label(over); 3034 return true; 3035 } 3036 return false; 3037} 3038 3039/* 3040 *** Vector Permutation Instructions 3041 */ 3042 3043static void load_element(TCGv_i64 dest, TCGv_ptr base, 3044 int ofs, int sew, bool sign) 3045{ 3046 switch (sew) { 3047 case MO_8: 3048 if (!sign) { 3049 tcg_gen_ld8u_i64(dest, base, ofs); 3050 } else { 3051 tcg_gen_ld8s_i64(dest, base, ofs); 3052 } 3053 break; 3054 case MO_16: 3055 if (!sign) { 3056 tcg_gen_ld16u_i64(dest, base, ofs); 3057 } else { 3058 tcg_gen_ld16s_i64(dest, base, ofs); 3059 } 3060 break; 3061 case MO_32: 3062 if (!sign) { 3063 tcg_gen_ld32u_i64(dest, base, ofs); 3064 } else { 3065 tcg_gen_ld32s_i64(dest, base, ofs); 3066 } 3067 break; 3068 case MO_64: 3069 tcg_gen_ld_i64(dest, base, ofs); 3070 break; 3071 default: 3072 g_assert_not_reached(); 3073 break; 3074 } 3075} 3076 3077/* offset of the idx element with base regsiter r */ 3078static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3079{ 3080#ifdef HOST_WORDS_BIGENDIAN 3081 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3082#else 3083 return vreg_ofs(s, r) + (idx << s->sew); 3084#endif 3085} 3086 3087/* adjust the index according to the endian */ 3088static void endian_adjust(TCGv_i32 ofs, int sew) 3089{ 3090#ifdef HOST_WORDS_BIGENDIAN 3091 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3092#endif 3093} 3094 3095/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3096static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3097 int vreg, TCGv idx, int vlmax) 3098{ 3099 TCGv_i32 ofs = tcg_temp_new_i32(); 3100 TCGv_ptr base = tcg_temp_new_ptr(); 3101 TCGv_i64 t_idx = tcg_temp_new_i64(); 3102 TCGv_i64 t_vlmax, t_zero; 3103 3104 /* 3105 * Mask the index to the length so that we do 3106 * not produce an out-of-range load. 3107 */ 3108 tcg_gen_trunc_tl_i32(ofs, idx); 3109 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3110 3111 /* Convert the index to an offset. */ 3112 endian_adjust(ofs, s->sew); 3113 tcg_gen_shli_i32(ofs, ofs, s->sew); 3114 3115 /* Convert the index to a pointer. */ 3116 tcg_gen_ext_i32_ptr(base, ofs); 3117 tcg_gen_add_ptr(base, base, cpu_env); 3118 3119 /* Perform the load. */ 3120 load_element(dest, base, 3121 vreg_ofs(s, vreg), s->sew, false); 3122 tcg_temp_free_ptr(base); 3123 tcg_temp_free_i32(ofs); 3124 3125 /* Flush out-of-range indexing to zero. */ 3126 t_vlmax = tcg_constant_i64(vlmax); 3127 t_zero = tcg_constant_i64(0); 3128 tcg_gen_extu_tl_i64(t_idx, idx); 3129 3130 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3131 t_vlmax, dest, t_zero); 3132 3133 tcg_temp_free_i64(t_idx); 3134} 3135 3136static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3137 int vreg, int idx, bool sign) 3138{ 3139 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign); 3140} 3141 3142/* Integer Scalar Move Instruction */ 3143 3144static void store_element(TCGv_i64 val, TCGv_ptr base, 3145 int ofs, int sew) 3146{ 3147 switch (sew) { 3148 case MO_8: 3149 tcg_gen_st8_i64(val, base, ofs); 3150 break; 3151 case MO_16: 3152 tcg_gen_st16_i64(val, base, ofs); 3153 break; 3154 case MO_32: 3155 tcg_gen_st32_i64(val, base, ofs); 3156 break; 3157 case MO_64: 3158 tcg_gen_st_i64(val, base, ofs); 3159 break; 3160 default: 3161 g_assert_not_reached(); 3162 break; 3163 } 3164} 3165 3166/* 3167 * Store vreg[idx] = val. 3168 * The index must be in range of VLMAX. 3169 */ 3170static void vec_element_storei(DisasContext *s, int vreg, 3171 int idx, TCGv_i64 val) 3172{ 3173 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 3174} 3175 3176/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3177static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3178{ 3179 if (require_rvv(s) && 3180 vext_check_isa_ill(s)) { 3181 TCGv_i64 t1; 3182 TCGv dest; 3183 3184 t1 = tcg_temp_new_i64(); 3185 dest = tcg_temp_new(); 3186 /* 3187 * load vreg and sign-extend to 64 bits, 3188 * then truncate to XLEN bits before storing to gpr. 3189 */ 3190 vec_element_loadi(s, t1, a->rs2, 0, true); 3191 tcg_gen_trunc_i64_tl(dest, t1); 3192 gen_set_gpr(s, a->rd, dest); 3193 tcg_temp_free_i64(t1); 3194 tcg_temp_free(dest); 3195 3196 return true; 3197 } 3198 return false; 3199} 3200 3201/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3202static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3203{ 3204 if (require_rvv(s) && 3205 vext_check_isa_ill(s)) { 3206 /* This instruction ignores LMUL and vector register groups */ 3207 TCGv_i64 t1; 3208 TCGv s1; 3209 TCGLabel *over = gen_new_label(); 3210 3211 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3212 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3213 3214 t1 = tcg_temp_new_i64(); 3215 3216 /* 3217 * load gpr and sign-extend to 64 bits, 3218 * then truncate to SEW bits when storing to vreg. 3219 */ 3220 s1 = get_gpr(s, a->rs1, EXT_NONE); 3221 tcg_gen_ext_tl_i64(t1, s1); 3222 vec_element_storei(s, a->rd, 0, t1); 3223 tcg_temp_free_i64(t1); 3224 mark_vs_dirty(s); 3225 gen_set_label(over); 3226 return true; 3227 } 3228 return false; 3229} 3230 3231/* Floating-Point Scalar Move Instructions */ 3232static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3233{ 3234 if (require_rvv(s) && 3235 require_rvf(s) && 3236 vext_check_isa_ill(s)) { 3237 gen_set_rm(s, RISCV_FRM_DYN); 3238 3239 unsigned int ofs = (8 << s->sew); 3240 unsigned int len = 64 - ofs; 3241 TCGv_i64 t_nan; 3242 3243 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3244 /* NaN-box f[rd] as necessary for SEW */ 3245 if (len) { 3246 t_nan = tcg_constant_i64(UINT64_MAX); 3247 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3248 t_nan, ofs, len); 3249 } 3250 3251 mark_fs_dirty(s); 3252 return true; 3253 } 3254 return false; 3255} 3256 3257/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3258static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3259{ 3260 if (require_rvv(s) && 3261 require_rvf(s) && 3262 vext_check_isa_ill(s)) { 3263 gen_set_rm(s, RISCV_FRM_DYN); 3264 3265 /* The instructions ignore LMUL and vector register group. */ 3266 TCGv_i64 t1; 3267 TCGLabel *over = gen_new_label(); 3268 3269 /* if vl == 0 or vstart >= vl, skip vector register write back */ 3270 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3271 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3272 3273 /* NaN-box f[rs1] */ 3274 t1 = tcg_temp_new_i64(); 3275 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3276 3277 vec_element_storei(s, a->rd, 0, t1); 3278 tcg_temp_free_i64(t1); 3279 mark_vs_dirty(s); 3280 gen_set_label(over); 3281 return true; 3282 } 3283 return false; 3284} 3285 3286/* Vector Slide Instructions */ 3287static bool slideup_check(DisasContext *s, arg_rmrr *a) 3288{ 3289 return require_rvv(s) && 3290 vext_check_isa_ill(s) && 3291 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3292} 3293 3294GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3295GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3296GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3297 3298static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3299{ 3300 return require_rvv(s) && 3301 vext_check_isa_ill(s) && 3302 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3303} 3304 3305GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3306GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3307GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3308 3309/* Vector Floating-Point Slide Instructions */ 3310static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3311{ 3312 return slideup_check(s, a) && 3313 require_rvf(s); 3314} 3315 3316static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3317{ 3318 return slidedown_check(s, a) && 3319 require_rvf(s); 3320} 3321 3322GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3323GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3324 3325/* Vector Register Gather Instruction */ 3326static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3327{ 3328 return require_rvv(s) && 3329 vext_check_isa_ill(s) && 3330 require_align(a->rd, s->lmul) && 3331 require_align(a->rs1, s->lmul) && 3332 require_align(a->rs2, s->lmul) && 3333 (a->rd != a->rs2 && a->rd != a->rs1) && 3334 require_vm(a->vm, a->rd); 3335} 3336 3337static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3338{ 3339 int8_t emul = MO_16 - s->sew + s->lmul; 3340 return require_rvv(s) && 3341 vext_check_isa_ill(s) && 3342 (emul >= -3 && emul <= 3) && 3343 require_align(a->rd, s->lmul) && 3344 require_align(a->rs1, emul) && 3345 require_align(a->rs2, s->lmul) && 3346 (a->rd != a->rs2 && a->rd != a->rs1) && 3347 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3348 a->rs1, 1 << MAX(emul, 0)) && 3349 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3350 a->rs2, 1 << MAX(s->lmul, 0)) && 3351 require_vm(a->vm, a->rd); 3352} 3353 3354GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3355GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3356 3357static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3358{ 3359 return require_rvv(s) && 3360 vext_check_isa_ill(s) && 3361 require_align(a->rd, s->lmul) && 3362 require_align(a->rs2, s->lmul) && 3363 (a->rd != a->rs2) && 3364 require_vm(a->vm, a->rd); 3365} 3366 3367/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3368static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3369{ 3370 if (!vrgather_vx_check(s, a)) { 3371 return false; 3372 } 3373 3374 if (a->vm && s->vl_eq_vlmax) { 3375 int scale = s->lmul - (s->sew + 3); 3376 int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale; 3377 TCGv_i64 dest = tcg_temp_new_i64(); 3378 3379 if (a->rs1 == 0) { 3380 vec_element_loadi(s, dest, a->rs2, 0, false); 3381 } else { 3382 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3383 } 3384 3385 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3386 MAXSZ(s), MAXSZ(s), dest); 3387 tcg_temp_free_i64(dest); 3388 mark_vs_dirty(s); 3389 } else { 3390 static gen_helper_opivx * const fns[4] = { 3391 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3392 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3393 }; 3394 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3395 } 3396 return true; 3397} 3398 3399/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3400static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3401{ 3402 if (!vrgather_vx_check(s, a)) { 3403 return false; 3404 } 3405 3406 if (a->vm && s->vl_eq_vlmax) { 3407 int scale = s->lmul - (s->sew + 3); 3408 int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale; 3409 if (a->rs1 >= vlmax) { 3410 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3411 MAXSZ(s), MAXSZ(s), 0); 3412 } else { 3413 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3414 endian_ofs(s, a->rs2, a->rs1), 3415 MAXSZ(s), MAXSZ(s)); 3416 } 3417 mark_vs_dirty(s); 3418 } else { 3419 static gen_helper_opivx * const fns[4] = { 3420 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3421 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3422 }; 3423 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3424 s, IMM_ZX); 3425 } 3426 return true; 3427} 3428 3429/* 3430 * Vector Compress Instruction 3431 * 3432 * The destination vector register group cannot overlap the 3433 * source vector register group or the source mask register. 3434 */ 3435static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3436{ 3437 return require_rvv(s) && 3438 vext_check_isa_ill(s) && 3439 require_align(a->rd, s->lmul) && 3440 require_align(a->rs2, s->lmul) && 3441 (a->rd != a->rs2) && 3442 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3443 (s->vstart == 0); 3444} 3445 3446static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3447{ 3448 if (vcompress_vm_check(s, a)) { 3449 uint32_t data = 0; 3450 static gen_helper_gvec_4_ptr * const fns[4] = { 3451 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3452 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3453 }; 3454 TCGLabel *over = gen_new_label(); 3455 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3456 3457 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3458 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3459 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3460 cpu_env, s->vlen / 8, s->vlen / 8, data, 3461 fns[s->sew]); 3462 mark_vs_dirty(s); 3463 gen_set_label(over); 3464 return true; 3465 } 3466 return false; 3467} 3468 3469/* 3470 * Whole Vector Register Move Instructions ignore vtype and vl setting. 3471 * Thus, we don't need to check vill bit. (Section 16.6) 3472 */ 3473#define GEN_VMV_WHOLE_TRANS(NAME, LEN, SEQ) \ 3474static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3475{ \ 3476 if (require_rvv(s) && \ 3477 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3478 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3479 uint32_t maxsz = (s->vlen >> 3) * LEN; \ 3480 if (s->vstart == 0) { \ 3481 /* EEW = 8 */ \ 3482 tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd), \ 3483 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3484 mark_vs_dirty(s); \ 3485 } else { \ 3486 TCGLabel *over = gen_new_label(); \ 3487 tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ 3488 \ 3489 static gen_helper_gvec_2_ptr * const fns[4] = { \ 3490 gen_helper_vmv1r_v, gen_helper_vmv2r_v, \ 3491 gen_helper_vmv4r_v, gen_helper_vmv8r_v, \ 3492 }; \ 3493 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3494 cpu_env, maxsz, maxsz, 0, fns[SEQ]); \ 3495 mark_vs_dirty(s); \ 3496 gen_set_label(over); \ 3497 } \ 3498 return true; \ 3499 } \ 3500 return false; \ 3501} 3502 3503GEN_VMV_WHOLE_TRANS(vmv1r_v, 1, 0) 3504GEN_VMV_WHOLE_TRANS(vmv2r_v, 2, 1) 3505GEN_VMV_WHOLE_TRANS(vmv4r_v, 4, 2) 3506GEN_VMV_WHOLE_TRANS(vmv8r_v, 8, 3) 3507 3508static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3509{ 3510 uint8_t from = (s->sew + 3) - div; 3511 bool ret = require_rvv(s) && 3512 (from >= 3 && from <= 8) && 3513 (a->rd != a->rs2) && 3514 require_align(a->rd, s->lmul) && 3515 require_align(a->rs2, s->lmul - div) && 3516 require_vm(a->vm, a->rd) && 3517 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3518 return ret; 3519} 3520 3521static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3522{ 3523 uint32_t data = 0; 3524 gen_helper_gvec_3_ptr *fn; 3525 TCGLabel *over = gen_new_label(); 3526 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3527 3528 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3529 { 3530 NULL, gen_helper_vzext_vf2_h, 3531 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3532 }, 3533 { 3534 NULL, NULL, 3535 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3536 }, 3537 { 3538 NULL, NULL, 3539 NULL, gen_helper_vzext_vf8_d 3540 }, 3541 { 3542 NULL, gen_helper_vsext_vf2_h, 3543 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3544 }, 3545 { 3546 NULL, NULL, 3547 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3548 }, 3549 { 3550 NULL, NULL, 3551 NULL, gen_helper_vsext_vf8_d 3552 } 3553 }; 3554 3555 fn = fns[seq][s->sew]; 3556 if (fn == NULL) { 3557 return false; 3558 } 3559 3560 data = FIELD_DP32(data, VDATA, VM, a->vm); 3561 3562 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3563 vreg_ofs(s, a->rs2), cpu_env, 3564 s->vlen / 8, s->vlen / 8, data, fn); 3565 3566 mark_vs_dirty(s); 3567 gen_set_label(over); 3568 return true; 3569} 3570 3571/* Vector Integer Extension */ 3572#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3573static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3574{ \ 3575 if (int_ext_check(s, a, DIV)) { \ 3576 return int_ext_op(s, a, SEQ); \ 3577 } \ 3578 return false; \ 3579} 3580 3581GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3582GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3583GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3584GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3585GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3586GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3587