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