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