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