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