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