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) && 2002 s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true); 2003} 2004 2005static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a) 2006{ 2007 /* 2008 * All Zve* extensions support all vector integer instructions, 2009 * except that the vmulh integer multiply variants 2010 * that return the high word of the product 2011 * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) 2012 * are not included for EEW=64 in Zve64*. (Section 18.2) 2013 */ 2014 return opivx_check(s, a) && 2015 (!has_ext(s, RVV) && 2016 s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true); 2017} 2018 2019GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 2020GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check) 2021GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check) 2022GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check) 2023GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 2024GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check) 2025GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check) 2026GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check) 2027 2028/* Vector Integer Divide Instructions */ 2029GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 2030GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 2031GEN_OPIVV_TRANS(vremu_vv, opivv_check) 2032GEN_OPIVV_TRANS(vrem_vv, opivv_check) 2033GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 2034GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 2035GEN_OPIVX_TRANS(vremu_vx, opivx_check) 2036GEN_OPIVX_TRANS(vrem_vx, opivx_check) 2037 2038/* Vector Widening Integer Multiply Instructions */ 2039GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 2040GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 2041GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 2042GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 2043GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 2044GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 2045 2046/* Vector Single-Width Integer Multiply-Add Instructions */ 2047GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 2048GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 2049GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 2050GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 2051GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 2052GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 2053GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 2054GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 2055 2056/* Vector Widening Integer Multiply-Add Instructions */ 2057GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 2058GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 2059GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 2060GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 2061GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 2062GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 2063GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 2064 2065/* Vector Integer Merge and Move Instructions */ 2066static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 2067{ 2068 if (require_rvv(s) && 2069 vext_check_isa_ill(s) && 2070 /* vmv.v.v has rs2 = 0 and vm = 1 */ 2071 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 2072 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2073 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 2074 vreg_ofs(s, a->rs1), 2075 MAXSZ(s), MAXSZ(s)); 2076 } else { 2077 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2078 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2079 static gen_helper_gvec_2_ptr * const fns[4] = { 2080 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 2081 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 2082 }; 2083 TCGLabel *over = gen_new_label(); 2084 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2085 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2086 2087 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 2088 cpu_env, s->cfg_ptr->vlen / 8, 2089 s->cfg_ptr->vlen / 8, data, 2090 fns[s->sew]); 2091 gen_set_label(over); 2092 } 2093 mark_vs_dirty(s); 2094 return true; 2095 } 2096 return false; 2097} 2098 2099typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 2100static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 2101{ 2102 if (require_rvv(s) && 2103 vext_check_isa_ill(s) && 2104 /* vmv.v.x has rs2 = 0 and vm = 1 */ 2105 vext_check_ss(s, a->rd, 0, 1)) { 2106 TCGv s1; 2107 TCGLabel *over = gen_new_label(); 2108 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2109 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2110 2111 s1 = get_gpr(s, a->rs1, EXT_SIGN); 2112 2113 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2114 if (get_xl(s) == MXL_RV32 && s->sew == MO_64) { 2115 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2116 tcg_gen_ext_tl_i64(s1_i64, s1); 2117 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2118 MAXSZ(s), MAXSZ(s), s1_i64); 2119 tcg_temp_free_i64(s1_i64); 2120 } else { 2121 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 2122 MAXSZ(s), MAXSZ(s), s1); 2123 } 2124 } else { 2125 TCGv_i32 desc; 2126 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 2127 TCGv_ptr dest = tcg_temp_new_ptr(); 2128 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2129 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2130 static gen_helper_vmv_vx * const fns[4] = { 2131 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2132 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2133 }; 2134 2135 tcg_gen_ext_tl_i64(s1_i64, s1); 2136 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 2137 s->cfg_ptr->vlen / 8, data)); 2138 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2139 fns[s->sew](dest, s1_i64, cpu_env, desc); 2140 2141 tcg_temp_free_ptr(dest); 2142 tcg_temp_free_i64(s1_i64); 2143 } 2144 2145 mark_vs_dirty(s); 2146 gen_set_label(over); 2147 return true; 2148 } 2149 return false; 2150} 2151 2152static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 2153{ 2154 if (require_rvv(s) && 2155 vext_check_isa_ill(s) && 2156 /* vmv.v.i has rs2 = 0 and vm = 1 */ 2157 vext_check_ss(s, a->rd, 0, 1)) { 2158 int64_t simm = sextract64(a->rs1, 0, 5); 2159 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2160 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 2161 MAXSZ(s), MAXSZ(s), simm); 2162 mark_vs_dirty(s); 2163 } else { 2164 TCGv_i32 desc; 2165 TCGv_i64 s1; 2166 TCGv_ptr dest; 2167 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2168 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2169 static gen_helper_vmv_vx * const fns[4] = { 2170 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 2171 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 2172 }; 2173 TCGLabel *over = gen_new_label(); 2174 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2175 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2176 2177 s1 = tcg_constant_i64(simm); 2178 dest = tcg_temp_new_ptr(); 2179 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 2180 s->cfg_ptr->vlen / 8, data)); 2181 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2182 fns[s->sew](dest, s1, cpu_env, desc); 2183 2184 tcg_temp_free_ptr(dest); 2185 mark_vs_dirty(s); 2186 gen_set_label(over); 2187 } 2188 return true; 2189 } 2190 return false; 2191} 2192 2193GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 2194GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 2195GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 2196 2197/* 2198 *** Vector Fixed-Point Arithmetic Instructions 2199 */ 2200 2201/* Vector Single-Width Saturating Add and Subtract */ 2202GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 2203GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 2204GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 2205GEN_OPIVV_TRANS(vssub_vv, opivv_check) 2206GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 2207GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 2208GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 2209GEN_OPIVX_TRANS(vssub_vx, opivx_check) 2210GEN_OPIVI_TRANS(vsaddu_vi, IMM_SX, vsaddu_vx, opivx_check) 2211GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 2212 2213/* Vector Single-Width Averaging Add and Subtract */ 2214GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 2215GEN_OPIVV_TRANS(vaaddu_vv, opivv_check) 2216GEN_OPIVV_TRANS(vasub_vv, opivv_check) 2217GEN_OPIVV_TRANS(vasubu_vv, opivv_check) 2218GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 2219GEN_OPIVX_TRANS(vaaddu_vx, opivx_check) 2220GEN_OPIVX_TRANS(vasub_vx, opivx_check) 2221GEN_OPIVX_TRANS(vasubu_vx, opivx_check) 2222 2223/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 2224 2225static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a) 2226{ 2227 /* 2228 * All Zve* extensions support all vector fixed-point arithmetic 2229 * instructions, except that vsmul.vv and vsmul.vx are not supported 2230 * for EEW=64 in Zve64*. (Section 18.2) 2231 */ 2232 return opivv_check(s, a) && 2233 (!has_ext(s, RVV) && 2234 s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true); 2235} 2236 2237static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a) 2238{ 2239 /* 2240 * All Zve* extensions support all vector fixed-point arithmetic 2241 * instructions, except that vsmul.vv and vsmul.vx are not supported 2242 * for EEW=64 in Zve64*. (Section 18.2) 2243 */ 2244 return opivx_check(s, a) && 2245 (!has_ext(s, RVV) && 2246 s->cfg_ptr->ext_zve64f ? s->sew != MO_64 : true); 2247} 2248 2249GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check) 2250GEN_OPIVX_TRANS(vsmul_vx, vsmul_vx_check) 2251 2252/* Vector Single-Width Scaling Shift Instructions */ 2253GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 2254GEN_OPIVV_TRANS(vssra_vv, opivv_check) 2255GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 2256GEN_OPIVX_TRANS(vssra_vx, opivx_check) 2257GEN_OPIVI_TRANS(vssrl_vi, IMM_TRUNC_SEW, vssrl_vx, opivx_check) 2258GEN_OPIVI_TRANS(vssra_vi, IMM_TRUNC_SEW, vssra_vx, opivx_check) 2259 2260/* Vector Narrowing Fixed-Point Clip Instructions */ 2261GEN_OPIWV_NARROW_TRANS(vnclipu_wv) 2262GEN_OPIWV_NARROW_TRANS(vnclip_wv) 2263GEN_OPIWX_NARROW_TRANS(vnclipu_wx) 2264GEN_OPIWX_NARROW_TRANS(vnclip_wx) 2265GEN_OPIWI_NARROW_TRANS(vnclipu_wi, IMM_ZX, vnclipu_wx) 2266GEN_OPIWI_NARROW_TRANS(vnclip_wi, IMM_ZX, vnclip_wx) 2267 2268/* 2269 *** Vector Float Point Arithmetic Instructions 2270 */ 2271 2272/* 2273 * As RVF-only cpus always have values NaN-boxed to 64-bits, 2274 * RVF and RVD can be treated equally. 2275 * We don't have to deal with the cases of: SEW > FLEN. 2276 * 2277 * If SEW < FLEN, check whether input fp register is a valid 2278 * NaN-boxed value, in which case the least-significant SEW bits 2279 * of the f regsiter are used, else the canonical NaN value is used. 2280 */ 2281static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 2282{ 2283 switch (s->sew) { 2284 case 1: 2285 gen_check_nanbox_h(out, in); 2286 break; 2287 case 2: 2288 gen_check_nanbox_s(out, in); 2289 break; 2290 case 3: 2291 tcg_gen_mov_i64(out, in); 2292 break; 2293 default: 2294 g_assert_not_reached(); 2295 } 2296} 2297 2298/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 2299 2300/* 2301 * If the current SEW does not correspond to a supported IEEE floating-point 2302 * type, an illegal instruction exception is raised. 2303 */ 2304static bool opfvv_check(DisasContext *s, arg_rmrr *a) 2305{ 2306 return require_rvv(s) && 2307 require_rvf(s) && 2308 vext_check_isa_ill(s) && 2309 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2310} 2311 2312/* OPFVV without GVEC IR */ 2313#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2314static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2315{ \ 2316 if (CHECK(s, a)) { \ 2317 uint32_t data = 0; \ 2318 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2319 gen_helper_##NAME##_h, \ 2320 gen_helper_##NAME##_w, \ 2321 gen_helper_##NAME##_d, \ 2322 }; \ 2323 TCGLabel *over = gen_new_label(); \ 2324 gen_set_rm(s, RISCV_FRM_DYN); \ 2325 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2326 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 2327 \ 2328 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2329 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2330 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2331 data = \ 2332 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 2333 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2334 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2335 vreg_ofs(s, a->rs1), \ 2336 vreg_ofs(s, a->rs2), cpu_env, \ 2337 s->cfg_ptr->vlen / 8, \ 2338 s->cfg_ptr->vlen / 8, data, \ 2339 fns[s->sew - 1]); \ 2340 mark_vs_dirty(s); \ 2341 gen_set_label(over); \ 2342 return true; \ 2343 } \ 2344 return false; \ 2345} 2346GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2347GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2348 2349typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2350 TCGv_env, TCGv_i32); 2351 2352static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2353 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2354{ 2355 TCGv_ptr dest, src2, mask; 2356 TCGv_i32 desc; 2357 TCGv_i64 t1; 2358 2359 TCGLabel *over = gen_new_label(); 2360 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2361 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2362 2363 dest = tcg_temp_new_ptr(); 2364 mask = tcg_temp_new_ptr(); 2365 src2 = tcg_temp_new_ptr(); 2366 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 2367 s->cfg_ptr->vlen / 8, data)); 2368 2369 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 2370 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 2371 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2372 2373 /* NaN-box f[rs1] */ 2374 t1 = tcg_temp_new_i64(); 2375 do_nanbox(s, t1, cpu_fpr[rs1]); 2376 2377 fn(dest, mask, t1, src2, cpu_env, desc); 2378 2379 tcg_temp_free_ptr(dest); 2380 tcg_temp_free_ptr(mask); 2381 tcg_temp_free_ptr(src2); 2382 tcg_temp_free_i64(t1); 2383 mark_vs_dirty(s); 2384 gen_set_label(over); 2385 return true; 2386} 2387 2388/* 2389 * If the current SEW does not correspond to a supported IEEE floating-point 2390 * type, an illegal instruction exception is raised 2391 */ 2392static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2393{ 2394 return require_rvv(s) && 2395 require_rvf(s) && 2396 vext_check_isa_ill(s) && 2397 vext_check_ss(s, a->rd, a->rs2, a->vm); 2398} 2399 2400/* OPFVF without GVEC IR */ 2401#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2402static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2403{ \ 2404 if (CHECK(s, a)) { \ 2405 uint32_t data = 0; \ 2406 static gen_helper_opfvf *const fns[3] = { \ 2407 gen_helper_##NAME##_h, \ 2408 gen_helper_##NAME##_w, \ 2409 gen_helper_##NAME##_d, \ 2410 }; \ 2411 gen_set_rm(s, RISCV_FRM_DYN); \ 2412 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2413 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2414 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2415 data = FIELD_DP32(data, VDATA, VTA_ALL_1S, \ 2416 s->cfg_vta_all_1s); \ 2417 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2418 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2419 fns[s->sew - 1], s); \ 2420 } \ 2421 return false; \ 2422} 2423 2424GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2425GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2426GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2427 2428/* Vector Widening Floating-Point Add/Subtract Instructions */ 2429static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2430{ 2431 return require_rvv(s) && 2432 require_scale_rvf(s) && 2433 (s->sew != MO_8) && 2434 vext_check_isa_ill(s) && 2435 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2436} 2437 2438/* OPFVV with WIDEN */ 2439#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2440static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2441{ \ 2442 if (CHECK(s, a)) { \ 2443 uint32_t data = 0; \ 2444 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2445 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2446 }; \ 2447 TCGLabel *over = gen_new_label(); \ 2448 gen_set_rm(s, RISCV_FRM_DYN); \ 2449 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2450 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over);\ 2451 \ 2452 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2453 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2454 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2455 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2456 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2457 vreg_ofs(s, a->rs1), \ 2458 vreg_ofs(s, a->rs2), cpu_env, \ 2459 s->cfg_ptr->vlen / 8, \ 2460 s->cfg_ptr->vlen / 8, data, \ 2461 fns[s->sew - 1]); \ 2462 mark_vs_dirty(s); \ 2463 gen_set_label(over); \ 2464 return true; \ 2465 } \ 2466 return false; \ 2467} 2468 2469GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2470GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2471 2472static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2473{ 2474 return require_rvv(s) && 2475 require_scale_rvf(s) && 2476 (s->sew != MO_8) && 2477 vext_check_isa_ill(s) && 2478 vext_check_ds(s, a->rd, a->rs2, a->vm); 2479} 2480 2481/* OPFVF with WIDEN */ 2482#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2483static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2484{ \ 2485 if (opfvf_widen_check(s, a)) { \ 2486 uint32_t data = 0; \ 2487 static gen_helper_opfvf *const fns[2] = { \ 2488 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2489 }; \ 2490 gen_set_rm(s, RISCV_FRM_DYN); \ 2491 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2492 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2493 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2494 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2495 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2496 fns[s->sew - 1], s); \ 2497 } \ 2498 return false; \ 2499} 2500 2501GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2502GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2503 2504static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2505{ 2506 return require_rvv(s) && 2507 require_scale_rvf(s) && 2508 (s->sew != MO_8) && 2509 vext_check_isa_ill(s) && 2510 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2511} 2512 2513/* WIDEN OPFVV with WIDEN */ 2514#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2515static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2516{ \ 2517 if (opfwv_widen_check(s, a)) { \ 2518 uint32_t data = 0; \ 2519 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2520 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2521 }; \ 2522 TCGLabel *over = gen_new_label(); \ 2523 gen_set_rm(s, RISCV_FRM_DYN); \ 2524 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2525 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 2526 \ 2527 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2528 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2529 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2530 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2531 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2532 vreg_ofs(s, a->rs1), \ 2533 vreg_ofs(s, a->rs2), cpu_env, \ 2534 s->cfg_ptr->vlen / 8, \ 2535 s->cfg_ptr->vlen / 8, data, \ 2536 fns[s->sew - 1]); \ 2537 mark_vs_dirty(s); \ 2538 gen_set_label(over); \ 2539 return true; \ 2540 } \ 2541 return false; \ 2542} 2543 2544GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2545GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2546 2547static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2548{ 2549 return require_rvv(s) && 2550 require_scale_rvf(s) && 2551 (s->sew != MO_8) && 2552 vext_check_isa_ill(s) && 2553 vext_check_dd(s, a->rd, a->rs2, a->vm); 2554} 2555 2556/* WIDEN OPFVF with WIDEN */ 2557#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2558static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2559{ \ 2560 if (opfwf_widen_check(s, a)) { \ 2561 uint32_t data = 0; \ 2562 static gen_helper_opfvf *const fns[2] = { \ 2563 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2564 }; \ 2565 gen_set_rm(s, RISCV_FRM_DYN); \ 2566 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2567 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2568 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2569 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2570 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2571 fns[s->sew - 1], s); \ 2572 } \ 2573 return false; \ 2574} 2575 2576GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2577GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2578 2579/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2580GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2581GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2582GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2583GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2584GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2585 2586/* Vector Widening Floating-Point Multiply */ 2587GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2588GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2589 2590/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2591GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2592GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2593GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2594GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2595GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2596GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2597GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2598GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2599GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2600GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2601GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2602GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2603GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2604GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2605GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2606GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2607 2608/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2609GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2610GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2611GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2612GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2613GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2614GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2615GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2616GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2617 2618/* Vector Floating-Point Square-Root Instruction */ 2619 2620/* 2621 * If the current SEW does not correspond to a supported IEEE floating-point 2622 * type, an illegal instruction exception is raised 2623 */ 2624static bool opfv_check(DisasContext *s, arg_rmr *a) 2625{ 2626 return require_rvv(s) && 2627 require_rvf(s) && 2628 vext_check_isa_ill(s) && 2629 /* OPFV instructions ignore vs1 check */ 2630 vext_check_ss(s, a->rd, a->rs2, a->vm); 2631} 2632 2633static bool do_opfv(DisasContext *s, arg_rmr *a, 2634 gen_helper_gvec_3_ptr *fn, 2635 bool (*checkfn)(DisasContext *, arg_rmr *), 2636 int rm) 2637{ 2638 if (checkfn(s, a)) { 2639 uint32_t data = 0; 2640 TCGLabel *over = gen_new_label(); 2641 gen_set_rm_chkfrm(s, rm); 2642 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2643 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2644 2645 data = FIELD_DP32(data, VDATA, VM, a->vm); 2646 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2647 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2648 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2649 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2650 vreg_ofs(s, a->rs2), cpu_env, 2651 s->cfg_ptr->vlen / 8, 2652 s->cfg_ptr->vlen / 8, data, fn); 2653 mark_vs_dirty(s); 2654 gen_set_label(over); 2655 return true; 2656 } 2657 return false; 2658} 2659 2660#define GEN_OPFV_TRANS(NAME, CHECK, FRM) \ 2661static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2662{ \ 2663 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2664 gen_helper_##NAME##_h, \ 2665 gen_helper_##NAME##_w, \ 2666 gen_helper_##NAME##_d \ 2667 }; \ 2668 return do_opfv(s, a, fns[s->sew - 1], CHECK, FRM); \ 2669} 2670 2671GEN_OPFV_TRANS(vfsqrt_v, opfv_check, RISCV_FRM_DYN) 2672GEN_OPFV_TRANS(vfrsqrt7_v, opfv_check, RISCV_FRM_DYN) 2673GEN_OPFV_TRANS(vfrec7_v, opfv_check, RISCV_FRM_DYN) 2674 2675/* Vector Floating-Point MIN/MAX Instructions */ 2676GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2677GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2678GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2679GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2680 2681/* Vector Floating-Point Sign-Injection Instructions */ 2682GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2683GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2684GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2685GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2686GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2687GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2688 2689/* Vector Floating-Point Compare Instructions */ 2690static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2691{ 2692 return require_rvv(s) && 2693 require_rvf(s) && 2694 vext_check_isa_ill(s) && 2695 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2696} 2697 2698GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2699GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2700GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2701GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2702 2703static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2704{ 2705 return require_rvv(s) && 2706 require_rvf(s) && 2707 vext_check_isa_ill(s) && 2708 vext_check_ms(s, a->rd, a->rs2); 2709} 2710 2711GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2712GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2713GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2714GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2715GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2716GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2717 2718/* Vector Floating-Point Classify Instruction */ 2719GEN_OPFV_TRANS(vfclass_v, opfv_check, RISCV_FRM_DYN) 2720 2721/* Vector Floating-Point Merge Instruction */ 2722GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2723 2724static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2725{ 2726 if (require_rvv(s) && 2727 require_rvf(s) && 2728 vext_check_isa_ill(s) && 2729 require_align(a->rd, s->lmul)) { 2730 gen_set_rm(s, RISCV_FRM_DYN); 2731 2732 TCGv_i64 t1; 2733 2734 if (s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 2735 t1 = tcg_temp_new_i64(); 2736 /* NaN-box f[rs1] */ 2737 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2738 2739 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2740 MAXSZ(s), MAXSZ(s), t1); 2741 mark_vs_dirty(s); 2742 } else { 2743 TCGv_ptr dest; 2744 TCGv_i32 desc; 2745 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2746 data = FIELD_DP32(data, VDATA, VTA, s->vta); 2747 data = FIELD_DP32(data, VDATA, VMA, s->vma); 2748 static gen_helper_vmv_vx * const fns[3] = { 2749 gen_helper_vmv_v_x_h, 2750 gen_helper_vmv_v_x_w, 2751 gen_helper_vmv_v_x_d, 2752 }; 2753 TCGLabel *over = gen_new_label(); 2754 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2755 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 2756 2757 t1 = tcg_temp_new_i64(); 2758 /* NaN-box f[rs1] */ 2759 do_nanbox(s, t1, cpu_fpr[a->rs1]); 2760 2761 dest = tcg_temp_new_ptr(); 2762 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 2763 s->cfg_ptr->vlen / 8, data)); 2764 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2765 2766 fns[s->sew - 1](dest, t1, cpu_env, desc); 2767 2768 tcg_temp_free_ptr(dest); 2769 mark_vs_dirty(s); 2770 gen_set_label(over); 2771 } 2772 tcg_temp_free_i64(t1); 2773 return true; 2774 } 2775 return false; 2776} 2777 2778/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2779#define GEN_OPFV_CVT_TRANS(NAME, HELPER, FRM) \ 2780static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2781{ \ 2782 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2783 gen_helper_##HELPER##_h, \ 2784 gen_helper_##HELPER##_w, \ 2785 gen_helper_##HELPER##_d \ 2786 }; \ 2787 return do_opfv(s, a, fns[s->sew - 1], opfv_check, FRM); \ 2788} 2789 2790GEN_OPFV_CVT_TRANS(vfcvt_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_DYN) 2791GEN_OPFV_CVT_TRANS(vfcvt_x_f_v, vfcvt_x_f_v, RISCV_FRM_DYN) 2792GEN_OPFV_CVT_TRANS(vfcvt_f_xu_v, vfcvt_f_xu_v, RISCV_FRM_DYN) 2793GEN_OPFV_CVT_TRANS(vfcvt_f_x_v, vfcvt_f_x_v, RISCV_FRM_DYN) 2794/* Reuse the helper functions from vfcvt.xu.f.v and vfcvt.x.f.v */ 2795GEN_OPFV_CVT_TRANS(vfcvt_rtz_xu_f_v, vfcvt_xu_f_v, RISCV_FRM_RTZ) 2796GEN_OPFV_CVT_TRANS(vfcvt_rtz_x_f_v, vfcvt_x_f_v, RISCV_FRM_RTZ) 2797 2798/* Widening Floating-Point/Integer Type-Convert Instructions */ 2799 2800/* 2801 * If the current SEW does not correspond to a supported IEEE floating-point 2802 * type, an illegal instruction exception is raised 2803 */ 2804static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2805{ 2806 return require_rvv(s) && 2807 vext_check_isa_ill(s) && 2808 vext_check_ds(s, a->rd, a->rs2, a->vm); 2809} 2810 2811static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) 2812{ 2813 return opfv_widen_check(s, a) && 2814 require_rvf(s); 2815} 2816 2817static bool opffv_widen_check(DisasContext *s, arg_rmr *a) 2818{ 2819 return opfv_widen_check(s, a) && 2820 require_scale_rvfmin(s) && 2821 (s->sew != MO_8); 2822} 2823 2824#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ 2825static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2826{ \ 2827 if (CHECK(s, a)) { \ 2828 uint32_t data = 0; \ 2829 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2830 gen_helper_##HELPER##_h, \ 2831 gen_helper_##HELPER##_w, \ 2832 }; \ 2833 TCGLabel *over = gen_new_label(); \ 2834 gen_set_rm_chkfrm(s, FRM); \ 2835 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2836 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 2837 \ 2838 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2839 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2840 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2841 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2842 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2843 vreg_ofs(s, a->rs2), cpu_env, \ 2844 s->cfg_ptr->vlen / 8, \ 2845 s->cfg_ptr->vlen / 8, data, \ 2846 fns[s->sew - 1]); \ 2847 mark_vs_dirty(s); \ 2848 gen_set_label(over); \ 2849 return true; \ 2850 } \ 2851 return false; \ 2852} 2853 2854GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2855 RISCV_FRM_DYN) 2856GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2857 RISCV_FRM_DYN) 2858GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v, opffv_widen_check, vfwcvt_f_f_v, 2859 RISCV_FRM_DYN) 2860/* Reuse the helper functions from vfwcvt.xu.f.v and vfwcvt.x.f.v */ 2861GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_xu_f_v, opxfv_widen_check, vfwcvt_xu_f_v, 2862 RISCV_FRM_RTZ) 2863GEN_OPFV_WIDEN_TRANS(vfwcvt_rtz_x_f_v, opxfv_widen_check, vfwcvt_x_f_v, 2864 RISCV_FRM_RTZ) 2865 2866static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) 2867{ 2868 return require_rvv(s) && 2869 require_scale_rvf(s) && 2870 vext_check_isa_ill(s) && 2871 /* OPFV widening instructions ignore vs1 check */ 2872 vext_check_ds(s, a->rd, a->rs2, a->vm); 2873} 2874 2875#define GEN_OPFXV_WIDEN_TRANS(NAME) \ 2876static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2877{ \ 2878 if (opfxv_widen_check(s, a)) { \ 2879 uint32_t data = 0; \ 2880 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2881 gen_helper_##NAME##_b, \ 2882 gen_helper_##NAME##_h, \ 2883 gen_helper_##NAME##_w, \ 2884 }; \ 2885 TCGLabel *over = gen_new_label(); \ 2886 gen_set_rm(s, RISCV_FRM_DYN); \ 2887 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2888 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 2889 \ 2890 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2891 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2892 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2893 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2894 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2895 vreg_ofs(s, a->rs2), cpu_env, \ 2896 s->cfg_ptr->vlen / 8, \ 2897 s->cfg_ptr->vlen / 8, data, \ 2898 fns[s->sew]); \ 2899 mark_vs_dirty(s); \ 2900 gen_set_label(over); \ 2901 return true; \ 2902 } \ 2903 return false; \ 2904} 2905 2906GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_xu_v) 2907GEN_OPFXV_WIDEN_TRANS(vfwcvt_f_x_v) 2908 2909/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2910 2911/* 2912 * If the current SEW does not correspond to a supported IEEE floating-point 2913 * type, an illegal instruction exception is raised 2914 */ 2915static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2916{ 2917 return require_rvv(s) && 2918 vext_check_isa_ill(s) && 2919 /* OPFV narrowing instructions ignore vs1 check */ 2920 vext_check_sd(s, a->rd, a->rs2, a->vm); 2921} 2922 2923static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) 2924{ 2925 return opfv_narrow_check(s, a) && 2926 require_rvf(s) && 2927 (s->sew != MO_64); 2928} 2929 2930static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) 2931{ 2932 return opfv_narrow_check(s, a) && 2933 require_scale_rvfmin(s) && 2934 (s->sew != MO_8); 2935} 2936 2937static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a) 2938{ 2939 return opfv_narrow_check(s, a) && 2940 require_scale_rvf(s) && 2941 (s->sew != MO_8); 2942} 2943 2944#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ 2945static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2946{ \ 2947 if (CHECK(s, a)) { \ 2948 uint32_t data = 0; \ 2949 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2950 gen_helper_##HELPER##_h, \ 2951 gen_helper_##HELPER##_w, \ 2952 }; \ 2953 TCGLabel *over = gen_new_label(); \ 2954 gen_set_rm_chkfrm(s, FRM); \ 2955 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2956 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 2957 \ 2958 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2959 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2960 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 2961 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 2962 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2963 vreg_ofs(s, a->rs2), cpu_env, \ 2964 s->cfg_ptr->vlen / 8, \ 2965 s->cfg_ptr->vlen / 8, data, \ 2966 fns[s->sew - 1]); \ 2967 mark_vs_dirty(s); \ 2968 gen_set_label(over); \ 2969 return true; \ 2970 } \ 2971 return false; \ 2972} 2973 2974GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_w, opfxv_narrow_check, vfncvt_f_xu_w, 2975 RISCV_FRM_DYN) 2976GEN_OPFV_NARROW_TRANS(vfncvt_f_x_w, opfxv_narrow_check, vfncvt_f_x_w, 2977 RISCV_FRM_DYN) 2978GEN_OPFV_NARROW_TRANS(vfncvt_f_f_w, opffv_narrow_check, vfncvt_f_f_w, 2979 RISCV_FRM_DYN) 2980/* Reuse the helper function from vfncvt.f.f.w */ 2981GEN_OPFV_NARROW_TRANS(vfncvt_rod_f_f_w, opffv_rod_narrow_check, vfncvt_f_f_w, 2982 RISCV_FRM_ROD) 2983 2984static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) 2985{ 2986 return require_rvv(s) && 2987 require_scale_rvf(s) && 2988 vext_check_isa_ill(s) && 2989 /* OPFV narrowing instructions ignore vs1 check */ 2990 vext_check_sd(s, a->rd, a->rs2, a->vm); 2991} 2992 2993#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ 2994static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2995{ \ 2996 if (opxfv_narrow_check(s, a)) { \ 2997 uint32_t data = 0; \ 2998 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2999 gen_helper_##HELPER##_b, \ 3000 gen_helper_##HELPER##_h, \ 3001 gen_helper_##HELPER##_w, \ 3002 }; \ 3003 TCGLabel *over = gen_new_label(); \ 3004 gen_set_rm_chkfrm(s, FRM); \ 3005 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 3006 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 3007 \ 3008 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3009 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3010 data = FIELD_DP32(data, VDATA, VTA, s->vta); \ 3011 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3012 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 3013 vreg_ofs(s, a->rs2), cpu_env, \ 3014 s->cfg_ptr->vlen / 8, \ 3015 s->cfg_ptr->vlen / 8, data, \ 3016 fns[s->sew]); \ 3017 mark_vs_dirty(s); \ 3018 gen_set_label(over); \ 3019 return true; \ 3020 } \ 3021 return false; \ 3022} 3023 3024GEN_OPXFV_NARROW_TRANS(vfncvt_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_DYN) 3025GEN_OPXFV_NARROW_TRANS(vfncvt_x_f_w, vfncvt_x_f_w, RISCV_FRM_DYN) 3026/* Reuse the helper functions from vfncvt.xu.f.w and vfncvt.x.f.w */ 3027GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_xu_f_w, vfncvt_xu_f_w, RISCV_FRM_RTZ) 3028GEN_OPXFV_NARROW_TRANS(vfncvt_rtz_x_f_w, vfncvt_x_f_w, RISCV_FRM_RTZ) 3029 3030/* 3031 *** Vector Reduction Operations 3032 */ 3033/* Vector Single-Width Integer Reduction Instructions */ 3034static bool reduction_check(DisasContext *s, arg_rmrr *a) 3035{ 3036 return require_rvv(s) && 3037 vext_check_isa_ill(s) && 3038 vext_check_reduction(s, a->rs2); 3039} 3040 3041GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 3042GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 3043GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 3044GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 3045GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 3046GEN_OPIVV_TRANS(vredand_vs, reduction_check) 3047GEN_OPIVV_TRANS(vredor_vs, reduction_check) 3048GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 3049 3050/* Vector Widening Integer Reduction Instructions */ 3051static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 3052{ 3053 return reduction_check(s, a) && (s->sew < MO_64) && 3054 ((s->sew + 1) <= (s->cfg_ptr->elen >> 4)); 3055} 3056 3057GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 3058GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 3059 3060/* Vector Single-Width Floating-Point Reduction Instructions */ 3061static bool freduction_check(DisasContext *s, arg_rmrr *a) 3062{ 3063 return reduction_check(s, a) && 3064 require_rvf(s); 3065} 3066 3067GEN_OPFVV_TRANS(vfredusum_vs, freduction_check) 3068GEN_OPFVV_TRANS(vfredosum_vs, freduction_check) 3069GEN_OPFVV_TRANS(vfredmax_vs, freduction_check) 3070GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) 3071 3072/* Vector Widening Floating-Point Reduction Instructions */ 3073static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) 3074{ 3075 return reduction_widen_check(s, a) && 3076 require_scale_rvf(s) && 3077 (s->sew != MO_8); 3078} 3079 3080GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) 3081GEN_OPFVV_WIDEN_TRANS(vfwredosum_vs, freduction_widen_check) 3082 3083/* 3084 *** Vector Mask Operations 3085 */ 3086 3087/* Vector Mask-Register Logical Instructions */ 3088#define GEN_MM_TRANS(NAME) \ 3089static bool trans_##NAME(DisasContext *s, arg_r *a) \ 3090{ \ 3091 if (require_rvv(s) && \ 3092 vext_check_isa_ill(s)) { \ 3093 uint32_t data = 0; \ 3094 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 3095 TCGLabel *over = gen_new_label(); \ 3096 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 3097 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); \ 3098 \ 3099 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3100 data = \ 3101 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 3102 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 3103 vreg_ofs(s, a->rs1), \ 3104 vreg_ofs(s, a->rs2), cpu_env, \ 3105 s->cfg_ptr->vlen / 8, \ 3106 s->cfg_ptr->vlen / 8, data, fn); \ 3107 mark_vs_dirty(s); \ 3108 gen_set_label(over); \ 3109 return true; \ 3110 } \ 3111 return false; \ 3112} 3113 3114GEN_MM_TRANS(vmand_mm) 3115GEN_MM_TRANS(vmnand_mm) 3116GEN_MM_TRANS(vmandn_mm) 3117GEN_MM_TRANS(vmxor_mm) 3118GEN_MM_TRANS(vmor_mm) 3119GEN_MM_TRANS(vmnor_mm) 3120GEN_MM_TRANS(vmorn_mm) 3121GEN_MM_TRANS(vmxnor_mm) 3122 3123/* Vector count population in mask vcpop */ 3124static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 3125{ 3126 if (require_rvv(s) && 3127 vext_check_isa_ill(s) && 3128 s->vstart == 0) { 3129 TCGv_ptr src2, mask; 3130 TCGv dst; 3131 TCGv_i32 desc; 3132 uint32_t data = 0; 3133 data = FIELD_DP32(data, VDATA, VM, a->vm); 3134 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3135 3136 mask = tcg_temp_new_ptr(); 3137 src2 = tcg_temp_new_ptr(); 3138 dst = dest_gpr(s, a->rd); 3139 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 3140 s->cfg_ptr->vlen / 8, data)); 3141 3142 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 3143 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 3144 3145 gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc); 3146 gen_set_gpr(s, a->rd, dst); 3147 3148 tcg_temp_free_ptr(mask); 3149 tcg_temp_free_ptr(src2); 3150 3151 return true; 3152 } 3153 return false; 3154} 3155 3156/* vmfirst find-first-set mask bit */ 3157static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 3158{ 3159 if (require_rvv(s) && 3160 vext_check_isa_ill(s) && 3161 s->vstart == 0) { 3162 TCGv_ptr src2, mask; 3163 TCGv dst; 3164 TCGv_i32 desc; 3165 uint32_t data = 0; 3166 data = FIELD_DP32(data, VDATA, VM, a->vm); 3167 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3168 3169 mask = tcg_temp_new_ptr(); 3170 src2 = tcg_temp_new_ptr(); 3171 dst = dest_gpr(s, a->rd); 3172 desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlen / 8, 3173 s->cfg_ptr->vlen / 8, data)); 3174 3175 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 3176 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 3177 3178 gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); 3179 gen_set_gpr(s, a->rd, dst); 3180 3181 tcg_temp_free_ptr(mask); 3182 tcg_temp_free_ptr(src2); 3183 return true; 3184 } 3185 return false; 3186} 3187 3188/* vmsbf.m set-before-first mask bit */ 3189/* vmsif.m set-includ-first mask bit */ 3190/* vmsof.m set-only-first mask bit */ 3191#define GEN_M_TRANS(NAME) \ 3192static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3193{ \ 3194 if (require_rvv(s) && \ 3195 vext_check_isa_ill(s) && \ 3196 require_vm(a->vm, a->rd) && \ 3197 (a->rd != a->rs2) && \ 3198 (s->vstart == 0)) { \ 3199 uint32_t data = 0; \ 3200 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 3201 TCGLabel *over = gen_new_label(); \ 3202 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 3203 \ 3204 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 3205 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 3206 data = \ 3207 FIELD_DP32(data, VDATA, VTA_ALL_1S, s->cfg_vta_all_1s);\ 3208 data = FIELD_DP32(data, VDATA, VMA, s->vma); \ 3209 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 3210 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 3211 cpu_env, s->cfg_ptr->vlen / 8, \ 3212 s->cfg_ptr->vlen / 8, \ 3213 data, fn); \ 3214 mark_vs_dirty(s); \ 3215 gen_set_label(over); \ 3216 return true; \ 3217 } \ 3218 return false; \ 3219} 3220 3221GEN_M_TRANS(vmsbf_m) 3222GEN_M_TRANS(vmsif_m) 3223GEN_M_TRANS(vmsof_m) 3224 3225/* 3226 * Vector Iota Instruction 3227 * 3228 * 1. The destination register cannot overlap the source register. 3229 * 2. If masked, cannot overlap the mask register ('v0'). 3230 * 3. An illegal instruction exception is raised if vstart is non-zero. 3231 */ 3232static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 3233{ 3234 if (require_rvv(s) && 3235 vext_check_isa_ill(s) && 3236 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 3237 require_vm(a->vm, a->rd) && 3238 require_align(a->rd, s->lmul) && 3239 (s->vstart == 0)) { 3240 uint32_t data = 0; 3241 TCGLabel *over = gen_new_label(); 3242 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3243 3244 data = FIELD_DP32(data, VDATA, VM, a->vm); 3245 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3246 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3247 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3248 static gen_helper_gvec_3_ptr * const fns[4] = { 3249 gen_helper_viota_m_b, gen_helper_viota_m_h, 3250 gen_helper_viota_m_w, gen_helper_viota_m_d, 3251 }; 3252 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3253 vreg_ofs(s, a->rs2), cpu_env, 3254 s->cfg_ptr->vlen / 8, 3255 s->cfg_ptr->vlen / 8, data, fns[s->sew]); 3256 mark_vs_dirty(s); 3257 gen_set_label(over); 3258 return true; 3259 } 3260 return false; 3261} 3262 3263/* Vector Element Index Instruction */ 3264static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 3265{ 3266 if (require_rvv(s) && 3267 vext_check_isa_ill(s) && 3268 require_align(a->rd, s->lmul) && 3269 require_vm(a->vm, a->rd)) { 3270 uint32_t data = 0; 3271 TCGLabel *over = gen_new_label(); 3272 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3273 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3274 3275 data = FIELD_DP32(data, VDATA, VM, a->vm); 3276 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3277 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3278 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3279 static gen_helper_gvec_2_ptr * const fns[4] = { 3280 gen_helper_vid_v_b, gen_helper_vid_v_h, 3281 gen_helper_vid_v_w, gen_helper_vid_v_d, 3282 }; 3283 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3284 cpu_env, s->cfg_ptr->vlen / 8, 3285 s->cfg_ptr->vlen / 8, 3286 data, fns[s->sew]); 3287 mark_vs_dirty(s); 3288 gen_set_label(over); 3289 return true; 3290 } 3291 return false; 3292} 3293 3294/* 3295 *** Vector Permutation Instructions 3296 */ 3297 3298static void load_element(TCGv_i64 dest, TCGv_ptr base, 3299 int ofs, int sew, bool sign) 3300{ 3301 switch (sew) { 3302 case MO_8: 3303 if (!sign) { 3304 tcg_gen_ld8u_i64(dest, base, ofs); 3305 } else { 3306 tcg_gen_ld8s_i64(dest, base, ofs); 3307 } 3308 break; 3309 case MO_16: 3310 if (!sign) { 3311 tcg_gen_ld16u_i64(dest, base, ofs); 3312 } else { 3313 tcg_gen_ld16s_i64(dest, base, ofs); 3314 } 3315 break; 3316 case MO_32: 3317 if (!sign) { 3318 tcg_gen_ld32u_i64(dest, base, ofs); 3319 } else { 3320 tcg_gen_ld32s_i64(dest, base, ofs); 3321 } 3322 break; 3323 case MO_64: 3324 tcg_gen_ld_i64(dest, base, ofs); 3325 break; 3326 default: 3327 g_assert_not_reached(); 3328 break; 3329 } 3330} 3331 3332/* offset of the idx element with base regsiter r */ 3333static uint32_t endian_ofs(DisasContext *s, int r, int idx) 3334{ 3335#if HOST_BIG_ENDIAN 3336 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 3337#else 3338 return vreg_ofs(s, r) + (idx << s->sew); 3339#endif 3340} 3341 3342/* adjust the index according to the endian */ 3343static void endian_adjust(TCGv_i32 ofs, int sew) 3344{ 3345#if HOST_BIG_ENDIAN 3346 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 3347#endif 3348} 3349 3350/* Load idx >= VLMAX ? 0 : vreg[idx] */ 3351static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 3352 int vreg, TCGv idx, int vlmax) 3353{ 3354 TCGv_i32 ofs = tcg_temp_new_i32(); 3355 TCGv_ptr base = tcg_temp_new_ptr(); 3356 TCGv_i64 t_idx = tcg_temp_new_i64(); 3357 TCGv_i64 t_vlmax, t_zero; 3358 3359 /* 3360 * Mask the index to the length so that we do 3361 * not produce an out-of-range load. 3362 */ 3363 tcg_gen_trunc_tl_i32(ofs, idx); 3364 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 3365 3366 /* Convert the index to an offset. */ 3367 endian_adjust(ofs, s->sew); 3368 tcg_gen_shli_i32(ofs, ofs, s->sew); 3369 3370 /* Convert the index to a pointer. */ 3371 tcg_gen_ext_i32_ptr(base, ofs); 3372 tcg_gen_add_ptr(base, base, cpu_env); 3373 3374 /* Perform the load. */ 3375 load_element(dest, base, 3376 vreg_ofs(s, vreg), s->sew, false); 3377 tcg_temp_free_ptr(base); 3378 tcg_temp_free_i32(ofs); 3379 3380 /* Flush out-of-range indexing to zero. */ 3381 t_vlmax = tcg_constant_i64(vlmax); 3382 t_zero = tcg_constant_i64(0); 3383 tcg_gen_extu_tl_i64(t_idx, idx); 3384 3385 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 3386 t_vlmax, dest, t_zero); 3387 3388 tcg_temp_free_i64(t_idx); 3389} 3390 3391static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 3392 int vreg, int idx, bool sign) 3393{ 3394 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew, sign); 3395} 3396 3397/* Integer Scalar Move Instruction */ 3398 3399static void store_element(TCGv_i64 val, TCGv_ptr base, 3400 int ofs, int sew) 3401{ 3402 switch (sew) { 3403 case MO_8: 3404 tcg_gen_st8_i64(val, base, ofs); 3405 break; 3406 case MO_16: 3407 tcg_gen_st16_i64(val, base, ofs); 3408 break; 3409 case MO_32: 3410 tcg_gen_st32_i64(val, base, ofs); 3411 break; 3412 case MO_64: 3413 tcg_gen_st_i64(val, base, ofs); 3414 break; 3415 default: 3416 g_assert_not_reached(); 3417 break; 3418 } 3419} 3420 3421/* 3422 * Store vreg[idx] = val. 3423 * The index must be in range of VLMAX. 3424 */ 3425static void vec_element_storei(DisasContext *s, int vreg, 3426 int idx, TCGv_i64 val) 3427{ 3428 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 3429} 3430 3431/* vmv.x.s rd, vs2 # x[rd] = vs2[0] */ 3432static bool trans_vmv_x_s(DisasContext *s, arg_vmv_x_s *a) 3433{ 3434 if (require_rvv(s) && 3435 vext_check_isa_ill(s)) { 3436 TCGv_i64 t1; 3437 TCGv dest; 3438 3439 t1 = tcg_temp_new_i64(); 3440 dest = tcg_temp_new(); 3441 /* 3442 * load vreg and sign-extend to 64 bits, 3443 * then truncate to XLEN bits before storing to gpr. 3444 */ 3445 vec_element_loadi(s, t1, a->rs2, 0, true); 3446 tcg_gen_trunc_i64_tl(dest, t1); 3447 gen_set_gpr(s, a->rd, dest); 3448 tcg_temp_free_i64(t1); 3449 tcg_temp_free(dest); 3450 3451 return true; 3452 } 3453 return false; 3454} 3455 3456/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 3457static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 3458{ 3459 if (require_rvv(s) && 3460 vext_check_isa_ill(s)) { 3461 /* This instruction ignores LMUL and vector register groups */ 3462 TCGv_i64 t1; 3463 TCGv s1; 3464 TCGLabel *over = gen_new_label(); 3465 3466 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3467 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3468 3469 t1 = tcg_temp_new_i64(); 3470 3471 /* 3472 * load gpr and sign-extend to 64 bits, 3473 * then truncate to SEW bits when storing to vreg. 3474 */ 3475 s1 = get_gpr(s, a->rs1, EXT_NONE); 3476 tcg_gen_ext_tl_i64(t1, s1); 3477 vec_element_storei(s, a->rd, 0, t1); 3478 tcg_temp_free_i64(t1); 3479 mark_vs_dirty(s); 3480 gen_set_label(over); 3481 return true; 3482 } 3483 return false; 3484} 3485 3486/* Floating-Point Scalar Move Instructions */ 3487static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 3488{ 3489 if (require_rvv(s) && 3490 require_rvf(s) && 3491 vext_check_isa_ill(s)) { 3492 gen_set_rm(s, RISCV_FRM_DYN); 3493 3494 unsigned int ofs = (8 << s->sew); 3495 unsigned int len = 64 - ofs; 3496 TCGv_i64 t_nan; 3497 3498 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0, false); 3499 /* NaN-box f[rd] as necessary for SEW */ 3500 if (len) { 3501 t_nan = tcg_constant_i64(UINT64_MAX); 3502 tcg_gen_deposit_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3503 t_nan, ofs, len); 3504 } 3505 3506 mark_fs_dirty(s); 3507 return true; 3508 } 3509 return false; 3510} 3511 3512/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3513static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3514{ 3515 if (require_rvv(s) && 3516 require_rvf(s) && 3517 vext_check_isa_ill(s)) { 3518 gen_set_rm(s, RISCV_FRM_DYN); 3519 3520 /* The instructions ignore LMUL and vector register group. */ 3521 TCGv_i64 t1; 3522 TCGLabel *over = gen_new_label(); 3523 3524 /* if vl == 0 or vstart >= vl, skip vector register write back */ 3525 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3526 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3527 3528 /* NaN-box f[rs1] */ 3529 t1 = tcg_temp_new_i64(); 3530 do_nanbox(s, t1, cpu_fpr[a->rs1]); 3531 3532 vec_element_storei(s, a->rd, 0, t1); 3533 tcg_temp_free_i64(t1); 3534 mark_vs_dirty(s); 3535 gen_set_label(over); 3536 return true; 3537 } 3538 return false; 3539} 3540 3541/* Vector Slide Instructions */ 3542static bool slideup_check(DisasContext *s, arg_rmrr *a) 3543{ 3544 return require_rvv(s) && 3545 vext_check_isa_ill(s) && 3546 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3547} 3548 3549GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3550GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3551GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3552 3553static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3554{ 3555 return require_rvv(s) && 3556 vext_check_isa_ill(s) && 3557 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3558} 3559 3560GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3561GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3562GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3563 3564/* Vector Floating-Point Slide Instructions */ 3565static bool fslideup_check(DisasContext *s, arg_rmrr *a) 3566{ 3567 return slideup_check(s, a) && 3568 require_rvf(s); 3569} 3570 3571static bool fslidedown_check(DisasContext *s, arg_rmrr *a) 3572{ 3573 return slidedown_check(s, a) && 3574 require_rvf(s); 3575} 3576 3577GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) 3578GEN_OPFVF_TRANS(vfslide1down_vf, fslidedown_check) 3579 3580/* Vector Register Gather Instruction */ 3581static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3582{ 3583 return require_rvv(s) && 3584 vext_check_isa_ill(s) && 3585 require_align(a->rd, s->lmul) && 3586 require_align(a->rs1, s->lmul) && 3587 require_align(a->rs2, s->lmul) && 3588 (a->rd != a->rs2 && a->rd != a->rs1) && 3589 require_vm(a->vm, a->rd); 3590} 3591 3592static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) 3593{ 3594 int8_t emul = MO_16 - s->sew + s->lmul; 3595 return require_rvv(s) && 3596 vext_check_isa_ill(s) && 3597 (emul >= -3 && emul <= 3) && 3598 require_align(a->rd, s->lmul) && 3599 require_align(a->rs1, emul) && 3600 require_align(a->rs2, s->lmul) && 3601 (a->rd != a->rs2 && a->rd != a->rs1) && 3602 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3603 a->rs1, 1 << MAX(emul, 0)) && 3604 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), 3605 a->rs2, 1 << MAX(s->lmul, 0)) && 3606 require_vm(a->vm, a->rd); 3607} 3608 3609GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3610GEN_OPIVV_TRANS(vrgatherei16_vv, vrgatherei16_vv_check) 3611 3612static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3613{ 3614 return require_rvv(s) && 3615 vext_check_isa_ill(s) && 3616 require_align(a->rd, s->lmul) && 3617 require_align(a->rs2, s->lmul) && 3618 (a->rd != a->rs2) && 3619 require_vm(a->vm, a->rd); 3620} 3621 3622/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3623static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3624{ 3625 if (!vrgather_vx_check(s, a)) { 3626 return false; 3627 } 3628 3629 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3630 int scale = s->lmul - (s->sew + 3); 3631 int vlmax = s->cfg_ptr->vlen >> -scale; 3632 TCGv_i64 dest = tcg_temp_new_i64(); 3633 3634 if (a->rs1 == 0) { 3635 vec_element_loadi(s, dest, a->rs2, 0, false); 3636 } else { 3637 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3638 } 3639 3640 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3641 MAXSZ(s), MAXSZ(s), dest); 3642 tcg_temp_free_i64(dest); 3643 mark_vs_dirty(s); 3644 } else { 3645 static gen_helper_opivx * const fns[4] = { 3646 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3647 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3648 }; 3649 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3650 } 3651 return true; 3652} 3653 3654/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3655static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3656{ 3657 if (!vrgather_vx_check(s, a)) { 3658 return false; 3659 } 3660 3661 if (a->vm && s->vl_eq_vlmax && !(s->vta && s->lmul < 0)) { 3662 int scale = s->lmul - (s->sew + 3); 3663 int vlmax = s->cfg_ptr->vlen >> -scale; 3664 if (a->rs1 >= vlmax) { 3665 tcg_gen_gvec_dup_imm(MO_64, vreg_ofs(s, a->rd), 3666 MAXSZ(s), MAXSZ(s), 0); 3667 } else { 3668 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3669 endian_ofs(s, a->rs2, a->rs1), 3670 MAXSZ(s), MAXSZ(s)); 3671 } 3672 mark_vs_dirty(s); 3673 } else { 3674 static gen_helper_opivx * const fns[4] = { 3675 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3676 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3677 }; 3678 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3679 s, IMM_ZX); 3680 } 3681 return true; 3682} 3683 3684/* 3685 * Vector Compress Instruction 3686 * 3687 * The destination vector register group cannot overlap the 3688 * source vector register group or the source mask register. 3689 */ 3690static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3691{ 3692 return require_rvv(s) && 3693 vext_check_isa_ill(s) && 3694 require_align(a->rd, s->lmul) && 3695 require_align(a->rs2, s->lmul) && 3696 (a->rd != a->rs2) && 3697 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1) && 3698 (s->vstart == 0); 3699} 3700 3701static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3702{ 3703 if (vcompress_vm_check(s, a)) { 3704 uint32_t data = 0; 3705 static gen_helper_gvec_4_ptr * const fns[4] = { 3706 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3707 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3708 }; 3709 TCGLabel *over = gen_new_label(); 3710 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3711 3712 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3713 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3714 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3715 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3716 cpu_env, s->cfg_ptr->vlen / 8, 3717 s->cfg_ptr->vlen / 8, data, 3718 fns[s->sew]); 3719 mark_vs_dirty(s); 3720 gen_set_label(over); 3721 return true; 3722 } 3723 return false; 3724} 3725 3726/* 3727 * Whole Vector Register Move Instructions ignore vtype and vl setting. 3728 * Thus, we don't need to check vill bit. (Section 16.6) 3729 */ 3730#define GEN_VMV_WHOLE_TRANS(NAME, LEN) \ 3731static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 3732{ \ 3733 if (require_rvv(s) && \ 3734 QEMU_IS_ALIGNED(a->rd, LEN) && \ 3735 QEMU_IS_ALIGNED(a->rs2, LEN)) { \ 3736 uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN; \ 3737 if (s->vstart == 0) { \ 3738 /* EEW = 8 */ \ 3739 tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd), \ 3740 vreg_ofs(s, a->rs2), maxsz, maxsz); \ 3741 mark_vs_dirty(s); \ 3742 } else { \ 3743 TCGLabel *over = gen_new_label(); \ 3744 tcg_gen_brcondi_tl(TCG_COND_GEU, cpu_vstart, maxsz, over); \ 3745 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), \ 3746 cpu_env, maxsz, maxsz, 0, gen_helper_vmvr_v); \ 3747 mark_vs_dirty(s); \ 3748 gen_set_label(over); \ 3749 } \ 3750 return true; \ 3751 } \ 3752 return false; \ 3753} 3754 3755GEN_VMV_WHOLE_TRANS(vmv1r_v, 1) 3756GEN_VMV_WHOLE_TRANS(vmv2r_v, 2) 3757GEN_VMV_WHOLE_TRANS(vmv4r_v, 4) 3758GEN_VMV_WHOLE_TRANS(vmv8r_v, 8) 3759 3760static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) 3761{ 3762 uint8_t from = (s->sew + 3) - div; 3763 bool ret = require_rvv(s) && 3764 (from >= 3 && from <= 8) && 3765 (a->rd != a->rs2) && 3766 require_align(a->rd, s->lmul) && 3767 require_align(a->rs2, s->lmul - div) && 3768 require_vm(a->vm, a->rd) && 3769 require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); 3770 return ret; 3771} 3772 3773static bool int_ext_op(DisasContext *s, arg_rmr *a, uint8_t seq) 3774{ 3775 uint32_t data = 0; 3776 gen_helper_gvec_3_ptr *fn; 3777 TCGLabel *over = gen_new_label(); 3778 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3779 tcg_gen_brcond_tl(TCG_COND_GEU, cpu_vstart, cpu_vl, over); 3780 3781 static gen_helper_gvec_3_ptr * const fns[6][4] = { 3782 { 3783 NULL, gen_helper_vzext_vf2_h, 3784 gen_helper_vzext_vf2_w, gen_helper_vzext_vf2_d 3785 }, 3786 { 3787 NULL, NULL, 3788 gen_helper_vzext_vf4_w, gen_helper_vzext_vf4_d, 3789 }, 3790 { 3791 NULL, NULL, 3792 NULL, gen_helper_vzext_vf8_d 3793 }, 3794 { 3795 NULL, gen_helper_vsext_vf2_h, 3796 gen_helper_vsext_vf2_w, gen_helper_vsext_vf2_d 3797 }, 3798 { 3799 NULL, NULL, 3800 gen_helper_vsext_vf4_w, gen_helper_vsext_vf4_d, 3801 }, 3802 { 3803 NULL, NULL, 3804 NULL, gen_helper_vsext_vf8_d 3805 } 3806 }; 3807 3808 fn = fns[seq][s->sew]; 3809 if (fn == NULL) { 3810 return false; 3811 } 3812 3813 data = FIELD_DP32(data, VDATA, VM, a->vm); 3814 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3815 data = FIELD_DP32(data, VDATA, VTA, s->vta); 3816 data = FIELD_DP32(data, VDATA, VMA, s->vma); 3817 3818 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3819 vreg_ofs(s, a->rs2), cpu_env, 3820 s->cfg_ptr->vlen / 8, 3821 s->cfg_ptr->vlen / 8, data, fn); 3822 3823 mark_vs_dirty(s); 3824 gen_set_label(over); 3825 return true; 3826} 3827 3828/* Vector Integer Extension */ 3829#define GEN_INT_EXT_TRANS(NAME, DIV, SEQ) \ 3830static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 3831{ \ 3832 if (int_ext_check(s, a, DIV)) { \ 3833 return int_ext_op(s, a, SEQ); \ 3834 } \ 3835 return false; \ 3836} 3837 3838GEN_INT_EXT_TRANS(vzext_vf2, 1, 0) 3839GEN_INT_EXT_TRANS(vzext_vf4, 2, 1) 3840GEN_INT_EXT_TRANS(vzext_vf8, 3, 2) 3841GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) 3842GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) 3843GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) 3844