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