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