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