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