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 vext_check_isa_ill(s) && 2617 vext_check_ds(s, a->rd, a->rs2, a->vm); 2618} 2619 2620static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) 2621{ 2622 return opfv_widen_check(s, a) && 2623 require_rvf(s); 2624} 2625 2626static bool opffv_widen_check(DisasContext *s, arg_rmr *a) 2627{ 2628 return opfv_widen_check(s, a) && 2629 require_scale_rvf(s) && 2630 (s->sew != MO_8); 2631} 2632 2633#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ 2634static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2635{ \ 2636 if (CHECK(s, a)) { \ 2637 if (FRM != RISCV_FRM_DYN) { \ 2638 gen_set_rm(s, RISCV_FRM_DYN); \ 2639 } \ 2640 \ 2641 uint32_t data = 0; \ 2642 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2643 gen_helper_##HELPER##_h, \ 2644 gen_helper_##HELPER##_w, \ 2645 }; \ 2646 TCGLabel *over = gen_new_label(); \ 2647 gen_set_rm(s, FRM); \ 2648 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2649 \ 2650 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2651 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2652 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2653 vreg_ofs(s, a->rs2), cpu_env, \ 2654 s->vlen / 8, s->vlen / 8, data, \ 2655 fns[s->sew - 1]); \ 2656 mark_vs_dirty(s); \ 2657 gen_set_label(over); \ 2658 return true; \ 2659 } \ 2660 return false; \ 2661} 2662 2663GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2664 RISCV_FRM_DYN) 2665GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2666 RISCV_FRM_DYN) 2667GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v, 2668 RISCV_FRM_DYN) 2669/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2670GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2671 RISCV_FRM_RTZ) 2672GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2673 RISCV_FRM_RTZ) 2674 2675static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2676{ 2677 return require_rvv(s) && 2678 require_scale_rvf(s) && 2679 vext_check_isa_ill(s) && 2680 /* OPFV widening instructions ignore vs1 check */ 2681 vext_check_ds(s, a->rd, a->rs2, a->vm); 2682} 2683 2684#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2685static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2686{ \ 2687 if (opfxv_widen_check(s, a)) { \ 2688 uint32_t data = 0; \ 2689 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2690 gen_helper_##NAME##_b, \ 2691 gen_helper_##NAME##_h, \ 2692 gen_helper_##NAME##_w, \ 2693 }; \ 2694 TCGLabel *over = gen_new_label(); \ 2695 gen_set_rm(s, RISCV_FRM_DYN); \ 2696 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2697 \ 2698 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2699 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2700 vreg_ofs(s, a->rs2), cpu_env, \ 2701 s->vlen / 8, s->vlen / 8, data, \ 2702 fns[s->sew]); \ 2703 mark_vs_dirty(s); \ 2704 gen_set_label(over); \ 2705 return true; \ 2706 } \ 2707 return false; \ 2708} 2709 2710GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 2711GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 2712 2713/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2714 2715/* 2716 * If the current SEW does not correspond to a supported IEEE floating-point 2717 * type, an illegal instruction exception is raised 2718 */ 2719static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2720{ 2721 return require_rvv(s) && 2722 vext_check_isa_ill(s) && 2723 /* OPFV narrowing instructions ignore vs1 check */ 2724 vext_check_sd(s, a->rd, a->rs2, a->vm); 2725} 2726 2727static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) 2728{ 2729 return opfv_narrow_check(s, a) && 2730 require_rvf(s) && 2731 (s->sew != MO_64); 2732} 2733 2734static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) 2735{ 2736 return opfv_narrow_check(s, a) && 2737 require_scale_rvf(s) && 2738 (s->sew != MO_8); 2739} 2740 2741#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ 2742static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2743{ \ 2744 if (CHECK(s, a)) { \ 2745 if (FRM != RISCV_FRM_DYN) { \ 2746 gen_set_rm(s, RISCV_FRM_DYN); \ 2747 } \ 2748 \ 2749 uint32_t data = 0; \ 2750 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2751 gen_helper_##HELPER##_h, \ 2752 gen_helper_##HELPER##_w, \ 2753 }; \ 2754 TCGLabel *over = gen_new_label(); \ 2755 gen_set_rm(s, FRM); \ 2756 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2757 \ 2758 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2759 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2760 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2761 vreg_ofs(s, a->rs2), cpu_env, \ 2762 s->vlen / 8, s->vlen / 8, data, \ 2763 fns[s->sew - 1]); \ 2764 mark_vs_dirty(s); \ 2765 gen_set_label(over); \ 2766 return true; \ 2767 } \ 2768 return false; \ 2769} 2770 2771GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w, 2772 RISCV_FRM_DYN) 2773GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w, 2774 RISCV_FRM_DYN) 2775GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2776 RISCV_FRM_DYN) 2777/* Reuse the helper function from vfncvt.f.f.w */ 2778GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2779 RISCV_FRM_ROD) 2780 2781static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 2782{ 2783 return require_rvv(s) && 2784 require_scale_rvf(s) && 2785 vext_check_isa_ill(s) && 2786 /* OPFV narrowing instructions ignore vs1 check */ 2787 vext_check_sd(s, a->rd, a->rs2, a->vm); 2788} 2789 2790#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2791static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2792{ \ 2793 if (opxfv_narrow_check(s, a)) { \ 2794 if (FRM != RISCV_FRM_DYN) { \ 2795 gen_set_rm(s, RISCV_FRM_DYN); \ 2796 } \ 2797 \ 2798 uint32_t data = 0; \ 2799 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2800 gen_helper_##HELPER##_b, \ 2801 gen_helper_##HELPER##_h, \ 2802 gen_helper_##HELPER##_w, \ 2803 }; \ 2804 TCGLabel *over = gen_new_label(); \ 2805 gen_set_rm(s, FRM); \ 2806 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2807 \ 2808 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2809 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2810 vreg_ofs(s, a->rs2), cpu_env, \ 2811 s->vlen / 8, s->vlen / 8, data, \ 2812 fns[s->sew]); \ 2813 mark_vs_dirty(s); \ 2814 gen_set_label(over); \ 2815 return true; \ 2816 } \ 2817 return false; \ 2818} 2819 2820GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 2821GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 2822/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 2823GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 2824GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 2825 2826/* 2827 *** Vector Reduction Operations 2828 */ 2829/* Vector Single-Width Integer Reduction Instructions */ 2830static bool reduction_check(DisasContext *s, arg_rmrr *a) 2831{ 2832 return require_rvv(s) && 2833 vext_check_isa_ill(s) && 2834 vext_check_reduction(s, a->rs2); 2835} 2836 2837GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2838GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2839GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2840GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2841GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2842GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2843GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2844GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2845 2846/* Vector Widening Integer Reduction Instructions */ 2847static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2848{ 2849 return reduction_check(s, a) && (s->sew < MO_64) && 2850 ((s->sew + 1) <= (s->elen >> 4)); 2851} 2852 2853GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2854GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2855 2856/* Vector Single-Width Floating-Point Reduction Instructions */ 2857static bool freduction_check(DisasContext *s, arg_rmrr *a) 2858{ 2859 return reduction_check(s, a) && 2860 require_rvf(s); 2861} 2862 2863GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) 2864GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 2865GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 2866 2867/* Vector Widening Floating-Point Reduction Instructions */ 2868static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 2869{ 2870 return reduction_widen_check(s, a) && 2871 require_scale_rvf(s) && 2872 (s->sew != MO_8); 2873} 2874 2875GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, freduction_widen_check) 2876 2877/* 2878 *** Vector Mask Operations 2879 */ 2880 2881/* Vector Mask-Register Logical Instructions */ 2882#define GEN_MM_TRANS(NAME) \ 2883static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2884{ \ 2885 if (require_rvv(s) && \ 2886 vext_check_isa_ill(s)) { \ 2887 uint32_t data = 0; \ 2888 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2889 TCGLabel *over = gen_new_label(); \ 2890 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2891 \ 2892 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2893 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2894 vreg_ofs(s, a->rs1), \ 2895 vreg_ofs(s, a->rs2), cpu_env, \ 2896 s->vlen / 8, s->vlen / 8, data, fn); \ 2897 mark_vs_dirty(s); \ 2898 gen_set_label(over); \ 2899 return true; \ 2900 } \ 2901 return false; \ 2902} 2903 2904GEN_MM_TRANS(vmand_mm) 2905GEN_MM_TRANS(vmnand_mm) 2906GEN_MM_TRANS(vmandn_mm) 2907GEN_MM_TRANS(vmxor_mm) 2908GEN_MM_TRANS(vmor_mm) 2909GEN_MM_TRANS(vmnor_mm) 2910GEN_MM_TRANS(vmorn_mm) 2911GEN_MM_TRANS(vmxnor_mm) 2912 2913/* Vector count population in mask vcpop */ 2914static bool trans_vcpop_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_vcpop_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 2940 return true; 2941 } 2942 return false; 2943} 2944 2945/* vmfirst find-first-set mask bit */ 2946static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 2947{ 2948 if (require_rvv(s) && 2949 vext_check_isa_ill(s) && 2950 s->vstart == 0) { 2951 TCGv_ptr src2, mask; 2952 TCGv dst; 2953 TCGv_i32 desc; 2954 uint32_t data = 0; 2955 data = FIELD_DP32(data, VDATA, VM, a->vm); 2956 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2957 2958 mask = tcg_temp_new_ptr(); 2959 src2 = tcg_temp_new_ptr(); 2960 dst = dest_gpr(s, a->rd); 2961 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2962 2963 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2964 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2965 2966 gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); 2967 gen_set_gpr(s, a->rd, dst); 2968 2969 tcg_temp_free_ptr(mask); 2970 tcg_temp_free_ptr(src2); 2971 return true; 2972 } 2973 return false; 2974} 2975 2976/* vmsbf.m set-before-first mask bit */ 2977/* vmsif.m set-includ-first mask bit */ 2978/* vmsof.m set-only-first mask bit */ 2979#define GEN_M_TRANS(NAME) \ 2980static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2981{ \ 2982 if (require_rvv(s) && \ 2983 vext_check_isa_ill(s) && \ 2984 require_vm(a->vm, a->rd) && \ 2985 (a->rd != a->rs2) && \ 2986 (s->vstart == 0)) { \ 2987 uint32_t data = 0; \ 2988 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2989 TCGLabel *over = gen_new_label(); \ 2990 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2991 \ 2992 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2993 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2994 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2995 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2996 cpu_env, s->vlen / 8, s->vlen / 8, \ 2997 data, fn); \ 2998 mark_vs_dirty(s); \ 2999 gen_set_label(over); \ 3000 return true; \ 3001 } \ 3002 return false; \ 3003} 3004 3005GEN_M_TRANS(vmsbf_m) 3006GEN_M_TRANS(vmsif_m) 3007GEN_M_TRANS(vmsof_m) 3008 3009/* 3010 * Vector Iota Instruction 3011 * 3012 * 1. The destination register cannot overlap the source register. 3013 * 2. If masked, cannot overlap the mask register ('v0'). 3014 * 3. An illegal instruction exception is raised if vstart is non-zero. 3015 */ 3016static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 3017{ 3018 if (require_rvv(s) && 3019 vext_check_isa_ill(s) && 3020 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 3021 require_vm(a->vm, a->rd) && 3022 require_align(a->rd, s->lmul) && 3023 (s->vstart == 0)) { 3024 uint32_t data = 0; 3025 TCGLabel *over = gen_new_label(); 3026 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3027 3028 data = FIELD_DP32(data, VDATA, VM, a->vm); 3029 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3030 static gen_helper_gvec_3_ptr * const fns[4] = { 3031 gen_helper_viota_m_b, gen_helper_viota_m_h, 3032 gen_helper_viota_m_w, gen_helper_viota_m_d, 3033 }; 3034 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3035 vreg_ofs(s, a->rs2), cpu_env, 3036 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 3037 mark_vs_dirty(s); 3038 gen_set_label(over); 3039 return true; 3040 } 3041 return false; 3042} 3043 3044/* Vector Element Index Instruction */ 3045static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3046{ 3047 if (require_rvv(s) && 3048 vext_check_isa_ill(s) && 3049 require_align(a->rd, s->lmul) && 3050 require_vm(a->vm, a->rd)) { 3051 uint32_t data = 0; 3052 TCGLabel *over = gen_new_label(); 3053 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3054 3055 data = FIELD_DP32(data, VDATA, VM, a->vm); 3056 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3057 static gen_helper_gvec_2_ptr * const fns[4] = { 3058 gen_helper_vid_v_b, gen_helper_vid_v_h, 3059 gen_helper_vid_v_w, gen_helper_vid_v_d, 3060 }; 3061 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3062 cpu_env, s->vlen / 8, s->vlen / 8, 3063 data, fns[s->sew]); 3064 mark_vs_dirty(s); 3065 gen_set_label(over); 3066 return true; 3067 } 3068 return false; 3069} 3070 3071/* 3072 *** Vector Permutation Instructions 3073 */ 3074 3075static void load_element(TCGv_i64 dest, TCGv_ptr base, 3076 int ofs, int sew, bool sign) 3077{ 3078 switch (sew) { 3079 case MO_8: 3080 if (!sign) { 3081 tcg_gen_ld8u_i64(dest, base, ofs); 3082 } else { 3083 tcg_gen_ld8s_i64(dest, base, ofs); 3084 } 3085 break; 3086 case MO_16: 3087 if (!sign) { 3088 tcg_gen_ld16u_i64(dest, base, ofs); 3089 } else { 3090 tcg_gen_ld16s_i64(dest, base, ofs); 3091 } 3092 break; 3093 case MO_32: 3094 if (!sign) { 3095 tcg_gen_ld32u_i64(dest, base, ofs); 3096 } else { 3097 tcg_gen_ld32s_i64(dest, base, ofs); 3098 } 3099 break; 3100 case MO_64: 3101 tcg_gen_ld_i64(dest, base, ofs); 3102 break; 3103 default: 3104 g_assert_not_reached(); 3105 break; 3106 } 3107} 3108 3109/* offset of the idx element with base regsiter r */ 3110static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3111{ 3112#ifdef HOST_WORDS_BIGENDIAN 3113 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3114#else 3115 return vreg_ofs(s, r) + (idx << s->sew); 3116#endif 3117} 3118 3119/* adjust the index according to the endian */ 3120static void endian_adjust(TCGv_i32 ofs, int sew) 3121{ 3122#ifdef HOST_WORDS_BIGENDIAN 3123 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3124#endif 3125} 3126 3127/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3128static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3129 int vreg, TCGv idx, int vlmax) 3130{ 3131 TCGv_i32 ofs = tcg_temp_new_i32(); 3132 TCGv_ptr base = tcg_temp_new_ptr(); 3133 TCGv_i64 t_idx = tcg_temp_new_i64(); 3134 TCGv_i64 t_vlmax, t_zero; 3135 3136 /* 3137 * Mask the index to the length so that we do 3138 * not produce an out-of-range load. 3139 */ 3140 tcg_gen_trunc_tl_i32(ofs, idx); 3141 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3142 3143 /* Convert the index to an offset. */ 3144 endian_adjust(ofs, s->sew); 3145 tcg_gen_shli_i32(ofs, ofs, s->sew); 3146 3147 /* Convert the index to a pointer. */ 3148 tcg_gen_ext_i32_ptr(base, ofs); 3149 tcg_gen_add_ptr(base, base, cpu_env); 3150 3151 /* Perform the load. */ 3152 load_element(dest, base, 3153 vreg_ofs(s, vreg), s->sew, false); 3154 tcg_temp_free_ptr(base); 3155 tcg_temp_free_i32(ofs); 3156 3157 /* Flush out-of-range indexing to zero. */ 3158 t_vlmax = tcg_constant_i64(vlmax); 3159 t_zero = tcg_constant_i64(0); 3160 tcg_gen_extu_tl_i64(t_idx, idx); 3161 3162 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3163 t_vlmax, dest, t_zero); 3164 3165 tcg_temp_free_i64(t_idx); 3166} 3167 3168static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3169 int vreg, int idx, bool sign) 3170{ 3171 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign); 3172} 3173 3174/* Integer Scalar Move Instruction */ 3175 3176static void store_element(TCGv_i64 val, TCGv_ptr base, 3177 int ofs, int sew) 3178{ 3179 switch (sew) { 3180 case MO_8: 3181 tcg_gen_st8_i64(val, base, ofs); 3182 break; 3183 case MO_16: 3184 tcg_gen_st16_i64(val, base, ofs); 3185 break; 3186 case MO_32: 3187 tcg_gen_st32_i64(val, base, ofs); 3188 break; 3189 case MO_64: 3190 tcg_gen_st_i64(val, base, ofs); 3191 break; 3192 default: 3193 g_assert_not_reached(); 3194 break; 3195 } 3196} 3197 3198/* 3199 * Store vreg[idx] = val. 3200 * The index must be in range of VLMAX. 3201 */ 3202static void vec_element_storei(DisasContext *s, int vreg, 3203 int idx, TCGv_i64 val) 3204{ 3205 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 3206} 3207 3208/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3209static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3210{ 3211 if (require_rvv(s) && 3212 vext_check_isa_ill(s)) { 3213 TCGv_i64 t1; 3214 TCGv dest; 3215 3216 t1 = tcg_temp_new_i64(); 3217 dest = tcg_temp_new(); 3218 /* 3219 * load vreg and sign-extend to 64 bits, 3220 * then truncate to XLEN bits before storing to gpr. 3221 */ 3222 vec_element_loadi(s, t1, a->rs2, 0, true); 3223 tcg_gen_trunc_i64_tl(dest, t1); 3224 gen_set_gpr(s, a->rd, dest); 3225 tcg_temp_free_i64(t1); 3226 tcg_temp_free(dest); 3227 3228 return true; 3229 } 3230 return false; 3231} 3232 3233/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3234static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3235{ 3236 if (require_rvv(s) && 3237 vext_check_isa_ill(s)) { 3238 /* This instruction ignores LMUL and vector register groups */ 3239 TCGv_i64 t1; 3240 TCGv s1; 3241 TCGLabel *over = gen_new_label(); 3242 3243 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3244 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3245 3246 t1 = tcg_temp_new_i64(); 3247 3248 /* 3249 * load gpr and sign-extend to 64 bits, 3250 * then truncate to SEW bits when storing to vreg. 3251 */ 3252 s1 = get_gpr(s, a->rs1, EXT_NONE); 3253 tcg_gen_ext_tl_i64(t1, s1); 3254 vec_element_storei(s, a->rd, 0, t1); 3255 tcg_temp_free_i64(t1); 3256 mark_vs_dirty(s); 3257 gen_set_label(over); 3258 return true; 3259 } 3260 return false; 3261} 3262 3263/* Floating-Point Scalar Move Instructions */ 3264static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3265{ 3266 if (require_rvv(s) && 3267 require_rvf(s) && 3268 vext_check_isa_ill(s)) { 3269 gen_set_rm(s, RISCV_FRM_DYN); 3270 3271 unsigned int ofs = (8 << s->sew); 3272 unsigned int len = 64 - ofs; 3273 TCGv_i64 t_nan; 3274 3275 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3276 /* NaN-box f[rd] as necessary for SEW */ 3277 if (len) { 3278 t_nan = tcg_constant_i64(UINT64_MAX); 3279 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3280 t_nan, ofs, len); 3281 } 3282 3283 mark_fs_dirty(s); 3284 return true; 3285 } 3286 return false; 3287} 3288 3289/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3290static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3291{ 3292 if (require_rvv(s) && 3293 require_rvf(s) && 3294 vext_check_isa_ill(s)) { 3295 gen_set_rm(s, RISCV_FRM_DYN); 3296 3297 /* The instructions ignore LMUL and vector register group. */ 3298 TCGv_i64 t1; 3299 TCGLabel *over = gen_new_label(); 3300 3301 /* if vl == 0 or vstart >= vl, skip vector register write back */ 3302 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3303 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3304 3305 /* NaN-box f[rs1] */ 3306 t1 = tcg_temp_new_i64(); 3307 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3308 3309 vec_element_storei(s, a->rd, 0, t1); 3310 tcg_temp_free_i64(t1); 3311 mark_vs_dirty(s); 3312 gen_set_label(over); 3313 return true; 3314 } 3315 return false; 3316} 3317 3318/* Vector Slide Instructions */ 3319static bool slideup_check(DisasContext *s, arg_rmrr *a) 3320{ 3321 return require_rvv(s) && 3322 vext_check_isa_ill(s) && 3323 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3324} 3325 3326GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3327GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3328GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3329 3330static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3331{ 3332 return require_rvv(s) && 3333 vext_check_isa_ill(s) && 3334 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3335} 3336 3337GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3338GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3339GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3340 3341/* Vector Floating-Point Slide Instructions */ 3342static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3343{ 3344 return slideup_check(s, a) && 3345 require_rvf(s); 3346} 3347 3348static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3349{ 3350 return slidedown_check(s, a) && 3351 require_rvf(s); 3352} 3353 3354GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3355GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3356 3357/* Vector Register Gather Instruction */ 3358static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3359{ 3360 return require_rvv(s) && 3361 vext_check_isa_ill(s) && 3362 require_align(a->rd, s->lmul) && 3363 require_align(a->rs1, s->lmul) && 3364 require_align(a->rs2, s->lmul) && 3365 (a->rd != a->rs2 && a->rd != a->rs1) && 3366 require_vm(a->vm, a->rd); 3367} 3368 3369static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3370{ 3371 int8_t emul = MO_16 - s->sew + s->lmul; 3372 return require_rvv(s) && 3373 vext_check_isa_ill(s) && 3374 (emul >= -3 && emul <= 3) && 3375 require_align(a->rd, s->lmul) && 3376 require_align(a->rs1, emul) && 3377 require_align(a->rs2, s->lmul) && 3378 (a->rd != a->rs2 && a->rd != a->rs1) && 3379 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3380 a->rs1, 1 << MAX(emul, 0)) && 3381 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3382 a->rs2, 1 << MAX(s->lmul, 0)) && 3383 require_vm(a->vm, a->rd); 3384} 3385 3386GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3387GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3388 3389static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3390{ 3391 return require_rvv(s) && 3392 vext_check_isa_ill(s) && 3393 require_align(a->rd, s->lmul) && 3394 require_align(a->rs2, s->lmul) && 3395 (a->rd != a->rs2) && 3396 require_vm(a->vm, a->rd); 3397} 3398 3399/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3400static bool trans_vrgather_vx(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 TCGv_i64 dest = tcg_temp_new_i64(); 3410 3411 if (a->rs1 == 0) { 3412 vec_element_loadi(s, dest, a->rs2, 0, false); 3413 } else { 3414 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3415 } 3416 3417 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3418 MAXSZ(s), MAXSZ(s), dest); 3419 tcg_temp_free_i64(dest); 3420 mark_vs_dirty(s); 3421 } else { 3422 static gen_helper_opivx * const fns[4] = { 3423 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3424 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3425 }; 3426 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3427 } 3428 return true; 3429} 3430 3431/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3432static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3433{ 3434 if (!vrgather_vx_check(s, a)) { 3435 return false; 3436 } 3437 3438 if (a->vm && s->vl_eq_vlmax) { 3439 int scale = s->lmul - (s->sew + 3); 3440 int vlmax = scale < 0 ? s->vlen >> -scale : s->vlen << scale; 3441 if (a->rs1 >= vlmax) { 3442 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3443 MAXSZ(s), MAXSZ(s), 0); 3444 } else { 3445 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3446 endian_ofs(s, a->rs2, a->rs1), 3447 MAXSZ(s), MAXSZ(s)); 3448 } 3449 mark_vs_dirty(s); 3450 } else { 3451 static gen_helper_opivx * const fns[4] = { 3452 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3453 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3454 }; 3455 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3456 s, IMM_ZX); 3457 } 3458 return true; 3459} 3460 3461/* 3462 * Vector Compress Instruction 3463 * 3464 * The destination vector register group cannot overlap the 3465 * source vector register group or the source mask register. 3466 */ 3467static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3468{ 3469 return require_rvv(s) && 3470 vext_check_isa_ill(s) && 3471 require_align(a->rd, s->lmul) && 3472 require_align(a->rs2, s->lmul) && 3473 (a->rd != a->rs2) && 3474 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3475 (s->vstart == 0); 3476} 3477 3478static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3479{ 3480 if (vcompress_vm_check(s, a)) { 3481 uint32_t data = 0; 3482 static gen_helper_gvec_4_ptr * const fns[4] = { 3483 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3484 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3485 }; 3486 TCGLabel *over = gen_new_label(); 3487 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3488 3489 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3490 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3491 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3492 cpu_env, s->vlen / 8, s->vlen / 8, data, 3493 fns[s->sew]); 3494 mark_vs_dirty(s); 3495 gen_set_label(over); 3496 return true; 3497 } 3498 return false; 3499} 3500 3501/* 3502 * Whole Vector Register Move Instructions ignore vtype and vl setting. 3503 * Thus, we don't need to check vill bit. (Section 16.6) 3504 */ 3505#define GEN_VMV_WHOLE_TRANS(NAME, LEN, SEQ) \ 3506static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3507{ \ 3508 if (require_rvv(s) && \ 3509 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3510 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3511 uint32_t maxsz = (s->vlen >> 3) * LEN; \ 3512 if (s->vstart == 0) { \ 3513 /* EEW = 8 */ \ 3514 tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd), \ 3515 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3516 mark_vs_dirty(s); \ 3517 } else { \ 3518 TCGLabel *over = gen_new_label(); \ 3519 tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ 3520 \ 3521 static gen_helper_gvec_2_ptr * const fns[4] = { \ 3522 gen_helper_vmv1r_v, gen_helper_vmv2r_v, \ 3523 gen_helper_vmv4r_v, gen_helper_vmv8r_v, \ 3524 }; \ 3525 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3526 cpu_env, maxsz, maxsz, 0, fns[SEQ]); \ 3527 mark_vs_dirty(s); \ 3528 gen_set_label(over); \ 3529 } \ 3530 return true; \ 3531 } \ 3532 return false; \ 3533} 3534 3535GEN_VMV_WHOLE_TRANS(vmv1r_v, 1, 0) 3536GEN_VMV_WHOLE_TRANS(vmv2r_v, 2, 1) 3537GEN_VMV_WHOLE_TRANS(vmv4r_v, 4, 2) 3538GEN_VMV_WHOLE_TRANS(vmv8r_v, 8, 3) 3539 3540static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3541{ 3542 uint8_t from = (s->sew + 3) - div; 3543 bool ret = require_rvv(s) && 3544 (from >= 3 && from <= 8) && 3545 (a->rd != a->rs2) && 3546 require_align(a->rd, s->lmul) && 3547 require_align(a->rs2, s->lmul - div) && 3548 require_vm(a->vm, a->rd) && 3549 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3550 return ret; 3551} 3552 3553static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3554{ 3555 uint32_t data = 0; 3556 gen_helper_gvec_3_ptr *fn; 3557 TCGLabel *over = gen_new_label(); 3558 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3559 3560 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3561 { 3562 NULL, gen_helper_vzext_vf2_h, 3563 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3564 }, 3565 { 3566 NULL, NULL, 3567 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3568 }, 3569 { 3570 NULL, NULL, 3571 NULL, gen_helper_vzext_vf8_d 3572 }, 3573 { 3574 NULL, gen_helper_vsext_vf2_h, 3575 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3576 }, 3577 { 3578 NULL, NULL, 3579 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3580 }, 3581 { 3582 NULL, NULL, 3583 NULL, gen_helper_vsext_vf8_d 3584 } 3585 }; 3586 3587 fn = fns[seq][s->sew]; 3588 if (fn == NULL) { 3589 return false; 3590 } 3591 3592 data = FIELD_DP32(data, VDATA, VM, a->vm); 3593 3594 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3595 vreg_ofs(s, a->rs2), cpu_env, 3596 s->vlen / 8, s->vlen / 8, data, fn); 3597 3598 mark_vs_dirty(s); 3599 gen_set_label(over); 3600 return true; 3601} 3602 3603/* Vector Integer Extension */ 3604#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3605static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3606{ \ 3607 if (int_ext_check(s, a, DIV)) { \ 3608 return int_ext_op(s, a, SEQ); \ 3609 } \ 3610 return false; \ 3611} 3612 3613GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3614GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3615GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3616GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3617GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3618GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3619