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