1/* 2 * RISC-V translation routines for the RVV Standard Extension. 3 * 4 * Copyright (c) 2020 T-Head Semiconductor Co., Ltd. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2 or later, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18#include "tcg/tcg-op-gvec.h" 19#include "tcg/tcg-gvec-desc.h" 20#include "internals.h" 21 22static inline bool is_overlapped(const int8_t astart, int8_t asize, 23 const int8_t bstart, int8_t bsize) 24{ 25 const int8_t aend = astart + asize; 26 const int8_t bend = bstart + bsize; 27 28 return MAX(aend, bend) - MIN(astart, bstart) < asize + bsize; 29} 30 31static bool require_rvv(DisasContext *s) 32{ 33 return s->mstatus_vs != 0; 34} 35 36static bool require_rvf(DisasContext *s) 37{ 38 if (s->mstatus_fs == 0) { 39 return false; 40 } 41 42 switch (s->sew) { 43 case MO_16: 44 case MO_32: 45 return has_ext(s, RVF); 46 case MO_64: 47 return has_ext(s, RVD); 48 default: 49 return false; 50 } 51} 52 53static bool require_scale_rvf(DisasContext *s) 54{ 55 if (s->mstatus_fs == 0) { 56 return false; 57 } 58 59 switch (s->sew) { 60 case MO_8: 61 case MO_16: 62 return has_ext(s, RVF); 63 case MO_32: 64 return has_ext(s, RVD); 65 default: 66 return false; 67 } 68} 69 70/* Destination vector register group cannot overlap source mask register. */ 71static bool require_vm(int vm, int vd) 72{ 73 return (vm != 0 || vd != 0); 74} 75 76static bool require_nf(int vd, int nf, int lmul) 77{ 78 int size = nf << MAX(lmul, 0); 79 return size <= 8 && vd + size <= 32; 80} 81 82/* 83 * Vector register should aligned with the passed-in LMUL (EMUL). 84 * If LMUL < 0, i.e. fractional LMUL, any vector register is allowed. 85 */ 86static bool require_align(const int8_t val, const int8_t lmul) 87{ 88 return lmul <= 0 || extract32(val, 0, lmul) == 0; 89} 90 91/* 92 * A destination vector register group can overlap a source vector 93 * register group only if one of the following holds: 94 * 1. The destination EEW equals the source EEW. 95 * 2. The destination EEW is smaller than the source EEW and the overlap 96 * is in the lowest-numbered part of the source register group. 97 * 3. The destination EEW is greater than the source EEW, the source EMUL 98 * is at least 1, and the overlap is in the highest-numbered part of 99 * the destination register group. 100 * (Section 5.2) 101 * 102 * This function returns true if one of the following holds: 103 * * Destination vector register group does not overlap a source vector 104 * register group. 105 * * Rule 3 met. 106 * For rule 1, overlap is allowed so this function doesn't need to be called. 107 * For rule 2, (vd == vs). Caller has to check whether: (vd != vs) before 108 * calling this function. 109 */ 110static bool require_noover(const int8_t dst, const int8_t dst_lmul, 111 const int8_t src, const int8_t src_lmul) 112{ 113 int8_t dst_size = dst_lmul <= 0 ? 1 : 1 << dst_lmul; 114 int8_t src_size = src_lmul <= 0 ? 1 : 1 << src_lmul; 115 116 /* Destination EEW is greater than the source EEW, check rule 3. */ 117 if (dst_size > src_size) { 118 if (dst < src && 119 src_lmul >= 0 && 120 is_overlapped(dst, dst_size, src, src_size) && 121 !is_overlapped(dst, dst_size, src + src_size, src_size)) { 122 return true; 123 } 124 } 125 126 return !is_overlapped(dst, dst_size, src, src_size); 127} 128 129static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) 130{ 131 TCGv s1, dst; 132 133 if (!require_rvv(s) || !has_ext(s, RVV)) { 134 return false; 135 } 136 137 dst = dest_gpr(s, rd); 138 139 if (rd == 0 && rs1 == 0) { 140 s1 = tcg_temp_new(); 141 tcg_gen_mov_tl(s1, cpu_vl); 142 } else if (rs1 == 0) { 143 /* As the mask is at least one bit, RV_VLEN_MAX is >= VLMAX */ 144 s1 = tcg_constant_tl(RV_VLEN_MAX); 145 } else { 146 s1 = get_gpr(s, rs1, EXT_ZERO); 147 } 148 149 gen_helper_vsetvl(dst, cpu_env, s1, s2); 150 gen_set_gpr(s, rd, dst); 151 mark_vs_dirty(s); 152 153 tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn); 154 tcg_gen_lookup_and_goto_ptr(); 155 s->base.is_jmp = DISAS_NORETURN; 156 157 if (rd == 0 && rs1 == 0) { 158 tcg_temp_free(s1); 159 } 160 161 return true; 162} 163 164static bool trans_vsetvl(DisasContext *s, arg_vsetvl *a) 165{ 166 TCGv s2 = get_gpr(s, a->rs2, EXT_ZERO); 167 return do_vsetvl(s, a->rd, a->rs1, s2); 168} 169 170static bool trans_vsetvli(DisasContext *s, arg_vsetvli *a) 171{ 172 TCGv s2 = tcg_constant_tl(a->zimm); 173 return do_vsetvl(s, a->rd, a->rs1, s2); 174} 175 176/* vector register offset from env */ 177static uint32_t vreg_ofs(DisasContext *s, int reg) 178{ 179 return offsetof(CPURISCVState, vreg) + reg * s->vlen / 8; 180} 181 182/* check functions */ 183 184/* 185 * Vector unit-stride, strided, unit-stride segment, strided segment 186 * store check function. 187 * 188 * Rules to be checked here: 189 * 1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3) 190 * 2. Destination vector register number is multiples of EMUL. 191 * (Section 3.4.2, 7.3) 192 * 3. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8) 193 * 4. Vector register numbers accessed by the segment load or store 194 * cannot increment past 31. (Section 7.8) 195 */ 196static bool vext_check_store(DisasContext *s, int vd, int nf, uint8_t eew) 197{ 198 int8_t emul = eew - s->sew + s->lmul; 199 return (emul >= -3 && emul <= 3) && 200 require_align(vd, emul) && 201 require_nf(vd, nf, emul); 202} 203 204/* 205 * Vector unit-stride, strided, unit-stride segment, strided segment 206 * load check function. 207 * 208 * Rules to be checked here: 209 * 1. All rules applies to store instructions are applies 210 * to load instructions. 211 * 2. Destination vector register group for a masked vector 212 * instruction cannot overlap the source mask register (v0). 213 * (Section 5.3) 214 */ 215static bool vext_check_load(DisasContext *s, int vd, int nf, int vm, 216 uint8_t eew) 217{ 218 return vext_check_store(s, vd, nf, eew) && require_vm(vm, vd); 219} 220 221/* 222 * Vector indexed, indexed segment store check function. 223 * 224 * Rules to be checked here: 225 * 1. EMUL must within the range: 1/8 <= EMUL <= 8. (Section 7.3) 226 * 2. Index vector register number is multiples of EMUL. 227 * (Section 3.4.2, 7.3) 228 * 3. Destination vector register number is multiples of LMUL. 229 * (Section 3.4.2, 7.3) 230 * 4. The EMUL setting must be such that EMUL * NFIELDS ≤ 8. (Section 7.8) 231 * 5. Vector register numbers accessed by the segment load or store 232 * cannot increment past 31. (Section 7.8) 233 */ 234static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf, 235 uint8_t eew) 236{ 237 int8_t emul = eew - s->sew + s->lmul; 238 return (emul >= -3 && emul <= 3) && 239 require_align(vs2, emul) && 240 require_align(vd, s->lmul) && 241 require_nf(vd, nf, s->lmul); 242} 243 244/* 245 * Vector indexed, indexed segment load check function. 246 * 247 * Rules to be checked here: 248 * 1. All rules applies to store instructions are applies 249 * to load instructions. 250 * 2. Destination vector register group for a masked vector 251 * instruction cannot overlap the source mask register (v0). 252 * (Section 5.3) 253 * 3. Destination vector register cannot overlap a source vector 254 * register (vs2) group. 255 * (Section 5.2) 256 * 4. Destination vector register groups cannot overlap 257 * the source vector register (vs2) group for 258 * indexed segment load instructions. (Section 7.8.3) 259 */ 260static bool vext_check_ld_index(DisasContext *s, int vd, int vs2, 261 int nf, int vm, uint8_t eew) 262{ 263 int8_t seg_vd; 264 int8_t emul = eew - s->sew + s->lmul; 265 bool ret = vext_check_st_index(s, vd, vs2, nf, eew) && 266 require_vm(vm, vd); 267 268 /* Each segment register group has to follow overlap rules. */ 269 for (int i = 0; i < nf; ++i) { 270 seg_vd = vd + (1 << MAX(s->lmul, 0)) * i; 271 272 if (eew > s->sew) { 273 if (seg_vd != vs2) { 274 ret &= require_noover(seg_vd, s->lmul, vs2, emul); 275 } 276 } else if (eew < s->sew) { 277 ret &= require_noover(seg_vd, s->lmul, vs2, emul); 278 } 279 280 /* 281 * Destination vector register groups cannot overlap 282 * the source vector register (vs2) group for 283 * indexed segment load instructions. 284 */ 285 if (nf > 1) { 286 ret &= !is_overlapped(seg_vd, 1 << MAX(s->lmul, 0), 287 vs2, 1 << MAX(emul, 0)); 288 } 289 } 290 return ret; 291} 292 293static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) 294{ 295 return require_vm(vm, vd) && 296 require_align(vd, s->lmul) && 297 require_align(vs, s->lmul); 298} 299 300/* 301 * Check function for vector instruction with format: 302 * single-width result and single-width sources (SEW = SEW op SEW) 303 * 304 * Rules to be checked here: 305 * 1. Destination vector register group for a masked vector 306 * instruction cannot overlap the source mask register (v0). 307 * (Section 5.3) 308 * 2. Destination vector register number is multiples of LMUL. 309 * (Section 3.4.2) 310 * 3. Source (vs2, vs1) vector register number are multiples of LMUL. 311 * (Section 3.4.2) 312 */ 313static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm) 314{ 315 return vext_check_ss(s, vd, vs2, vm) && 316 require_align(vs1, s->lmul); 317} 318 319static bool vext_check_ms(DisasContext *s, int vd, int vs) 320{ 321 bool ret = require_align(vs, s->lmul); 322 if (vd != vs) { 323 ret &= require_noover(vd, 0, vs, s->lmul); 324 } 325 return ret; 326} 327 328/* 329 * Check function for maskable vector instruction with format: 330 * single-width result and single-width sources (SEW = SEW op SEW) 331 * 332 * Rules to be checked here: 333 * 1. Source (vs2, vs1) vector register number are multiples of LMUL. 334 * (Section 3.4.2) 335 * 2. Destination vector register cannot overlap a source vector 336 * register (vs2, vs1) group. 337 * (Section 5.2) 338 * 3. The destination vector register group for a masked vector 339 * instruction cannot overlap the source mask register (v0), 340 * unless the destination vector register is being written 341 * with a mask value (e.g., comparisons) or the scalar result 342 * of a reduction. (Section 5.3) 343 */ 344static bool vext_check_mss(DisasContext *s, int vd, int vs1, int vs2) 345{ 346 bool ret = vext_check_ms(s, vd, vs2) && 347 require_align(vs1, s->lmul); 348 if (vd != vs1) { 349 ret &= require_noover(vd, 0, vs1, s->lmul); 350 } 351 return ret; 352} 353 354/* 355 * Common check function for vector widening instructions 356 * of double-width result (2*SEW). 357 * 358 * Rules to be checked here: 359 * 1. The largest vector register group used by an instruction 360 * can not be greater than 8 vector registers (Section 5.2): 361 * => LMUL < 8. 362 * => SEW < 64. 363 * 2. Destination vector register number is multiples of 2 * LMUL. 364 * (Section 3.4.2) 365 * 3. Destination vector register group for a masked vector 366 * instruction cannot overlap the source mask register (v0). 367 * (Section 5.3) 368 */ 369static bool vext_wide_check_common(DisasContext *s, int vd, int vm) 370{ 371 return (s->lmul <= 2) && 372 (s->sew < MO_64) && 373 require_align(vd, s->lmul + 1) && 374 require_vm(vm, vd); 375} 376 377/* 378 * Common check function for vector narrowing instructions 379 * of single-width result (SEW) and double-width source (2*SEW). 380 * 381 * Rules to be checked here: 382 * 1. The largest vector register group used by an instruction 383 * can not be greater than 8 vector registers (Section 5.2): 384 * => LMUL < 8. 385 * => SEW < 64. 386 * 2. Source vector register number is multiples of 2 * LMUL. 387 * (Section 3.4.2) 388 * 3. Destination vector register number is multiples of LMUL. 389 * (Section 3.4.2) 390 * 4. Destination vector register group for a masked vector 391 * instruction cannot overlap the source mask register (v0). 392 * (Section 5.3) 393 */ 394static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2, 395 int vm) 396{ 397 return (s->lmul <= 2) && 398 (s->sew < MO_64) && 399 require_align(vs2, s->lmul + 1) && 400 require_align(vd, s->lmul) && 401 require_vm(vm, vd); 402} 403 404static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) 405{ 406 return vext_wide_check_common(s, vd, vm) && 407 require_align(vs, s->lmul) && 408 require_noover(vd, s->lmul + 1, vs, s->lmul); 409} 410 411static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) 412{ 413 return vext_wide_check_common(s, vd, vm) && 414 require_align(vs, s->lmul + 1); 415} 416 417/* 418 * Check function for vector instruction with format: 419 * double-width result and single-width sources (2*SEW = SEW op SEW) 420 * 421 * Rules to be checked here: 422 * 1. All rules in defined in widen common rules are applied. 423 * 2. Source (vs2, vs1) vector register number are multiples of LMUL. 424 * (Section 3.4.2) 425 * 3. Destination vector register cannot overlap a source vector 426 * register (vs2, vs1) group. 427 * (Section 5.2) 428 */ 429static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) 430{ 431 return vext_check_ds(s, vd, vs2, vm) && 432 require_align(vs1, s->lmul) && 433 require_noover(vd, s->lmul + 1, vs1, s->lmul); 434} 435 436/* 437 * Check function for vector instruction with format: 438 * double-width result and double-width source1 and single-width 439 * source2 (2*SEW = 2*SEW op SEW) 440 * 441 * Rules to be checked here: 442 * 1. All rules in defined in widen common rules are applied. 443 * 2. Source 1 (vs2) vector register number is multiples of 2 * LMUL. 444 * (Section 3.4.2) 445 * 3. Source 2 (vs1) vector register number is multiples of LMUL. 446 * (Section 3.4.2) 447 * 4. Destination vector register cannot overlap a source vector 448 * register (vs1) group. 449 * (Section 5.2) 450 */ 451static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm) 452{ 453 return vext_check_ds(s, vd, vs1, vm) && 454 require_align(vs2, s->lmul + 1); 455} 456 457static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) 458{ 459 bool ret = vext_narrow_check_common(s, vd, vs, vm); 460 if (vd != vs) { 461 ret &= require_noover(vd, s->lmul, vs, s->lmul + 1); 462 } 463 return ret; 464} 465 466/* 467 * Check function for vector instruction with format: 468 * single-width result and double-width source 1 and single-width 469 * source 2 (SEW = 2*SEW op SEW) 470 * 471 * Rules to be checked here: 472 * 1. All rules in defined in narrow common rules are applied. 473 * 2. Destination vector register cannot overlap a source vector 474 * register (vs2) group. 475 * (Section 5.2) 476 * 3. Source 2 (vs1) vector register number is multiples of LMUL. 477 * (Section 3.4.2) 478 */ 479static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm) 480{ 481 return vext_check_sd(s, vd, vs2, vm) && 482 require_align(vs1, s->lmul); 483} 484 485/* 486 * Check function for vector reduction instructions. 487 * 488 * Rules to be checked here: 489 * 1. Source 1 (vs2) vector register number is multiples of LMUL. 490 * (Section 3.4.2) 491 */ 492static bool vext_check_reduction(DisasContext *s, int vs2) 493{ 494 return require_align(vs2, s->lmul); 495} 496 497/* 498 * Check function for vector slide instructions. 499 * 500 * Rules to be checked here: 501 * 1. Source 1 (vs2) vector register number is multiples of LMUL. 502 * (Section 3.4.2) 503 * 2. Destination vector register number is multiples of LMUL. 504 * (Section 3.4.2) 505 * 3. Destination vector register group for a masked vector 506 * instruction cannot overlap the source mask register (v0). 507 * (Section 5.3) 508 * 4. The destination vector register group for vslideup, vslide1up, 509 * vfslide1up, cannot overlap the source vector register (vs2) group. 510 * (Section 5.2, 16.3.1, 16.3.3) 511 */ 512static bool vext_check_slide(DisasContext *s, int vd, int vs2, 513 int vm, bool is_over) 514{ 515 bool ret = require_align(vs2, s->lmul) && 516 require_align(vd, s->lmul) && 517 require_vm(vm, vd); 518 if (is_over) { 519 ret &= (vd != vs2); 520 } 521 return ret; 522} 523 524/* 525 * In cpu_get_tb_cpu_state(), set VILL if RVV was not present. 526 * So RVV is also be checked in this function. 527 */ 528static bool vext_check_isa_ill(DisasContext *s) 529{ 530 return !s->vill; 531} 532 533/* common translation macro */ 534#define GEN_VEXT_TRANS(NAME, EEW, ARGTYPE, OP, CHECK) \ 535static bool trans_##NAME(DisasContext *s, arg_##ARGTYPE * a) \ 536{ \ 537 if (CHECK(s, a, EEW)) { \ 538 return OP(s, a, EEW); \ 539 } \ 540 return false; \ 541} 542 543/* 544 *** unit stride load and store 545 */ 546typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv, 547 TCGv_env, TCGv_i32); 548 549static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, 550 gen_helper_ldst_us *fn, DisasContext *s, 551 bool is_store) 552{ 553 TCGv_ptr dest, mask; 554 TCGv base; 555 TCGv_i32 desc; 556 557 TCGLabel *over = gen_new_label(); 558 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 559 560 dest = tcg_temp_new_ptr(); 561 mask = tcg_temp_new_ptr(); 562 base = get_gpr(s, rs1, EXT_NONE); 563 564 /* 565 * As simd_desc supports at most 256 bytes, and in this implementation, 566 * the max vector group length is 2048 bytes. So split it into two parts. 567 * 568 * The first part is vlen in bytes, encoded in maxsz of simd_desc. 569 * The second part is lmul, encoded in data of simd_desc. 570 */ 571 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 572 573 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 574 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 575 576 fn(dest, mask, base, cpu_env, desc); 577 578 tcg_temp_free_ptr(dest); 579 tcg_temp_free_ptr(mask); 580 581 if (!is_store) { 582 mark_vs_dirty(s); 583 } 584 585 gen_set_label(over); 586 return true; 587} 588 589static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 590{ 591 uint32_t data = 0; 592 gen_helper_ldst_us *fn; 593 static gen_helper_ldst_us * const fns[2][4] = { 594 /* masked unit stride load */ 595 { gen_helper_vle8_v_mask, gen_helper_vle16_v_mask, 596 gen_helper_vle32_v_mask, gen_helper_vle64_v_mask }, 597 /* unmasked unit stride load */ 598 { gen_helper_vle8_v, gen_helper_vle16_v, 599 gen_helper_vle32_v, gen_helper_vle64_v } 600 }; 601 602 fn = fns[a->vm][eew]; 603 if (fn == NULL) { 604 return false; 605 } 606 607 data = FIELD_DP32(data, VDATA, VM, a->vm); 608 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 609 data = FIELD_DP32(data, VDATA, NF, a->nf); 610 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 611} 612 613static bool ld_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 614{ 615 return require_rvv(s) && 616 vext_check_isa_ill(s) && 617 vext_check_load(s, a->rd, a->nf, a->vm, eew); 618} 619 620GEN_VEXT_TRANS(vle8_v, MO_8, r2nfvm, ld_us_op, ld_us_check) 621GEN_VEXT_TRANS(vle16_v, MO_16, r2nfvm, ld_us_op, ld_us_check) 622GEN_VEXT_TRANS(vle32_v, MO_32, r2nfvm, ld_us_op, ld_us_check) 623GEN_VEXT_TRANS(vle64_v, MO_64, r2nfvm, ld_us_op, ld_us_check) 624 625static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 626{ 627 uint32_t data = 0; 628 gen_helper_ldst_us *fn; 629 static gen_helper_ldst_us * const fns[2][4] = { 630 /* masked unit stride store */ 631 { gen_helper_vse8_v_mask, gen_helper_vse16_v_mask, 632 gen_helper_vse32_v_mask, gen_helper_vse64_v_mask }, 633 /* unmasked unit stride store */ 634 { gen_helper_vse8_v, gen_helper_vse16_v, 635 gen_helper_vse32_v, gen_helper_vse64_v } 636 }; 637 638 fn = fns[a->vm][eew]; 639 if (fn == NULL) { 640 return false; 641 } 642 643 data = FIELD_DP32(data, VDATA, VM, a->vm); 644 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 645 data = FIELD_DP32(data, VDATA, NF, a->nf); 646 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 647} 648 649static bool st_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 650{ 651 return require_rvv(s) && 652 vext_check_isa_ill(s) && 653 vext_check_store(s, a->rd, a->nf, eew); 654} 655 656GEN_VEXT_TRANS(vse8_v, MO_8, r2nfvm, st_us_op, st_us_check) 657GEN_VEXT_TRANS(vse16_v, MO_16, r2nfvm, st_us_op, st_us_check) 658GEN_VEXT_TRANS(vse32_v, MO_32, r2nfvm, st_us_op, st_us_check) 659GEN_VEXT_TRANS(vse64_v, MO_64, r2nfvm, st_us_op, st_us_check) 660 661/* 662 *** stride load and store 663 */ 664typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, 665 TCGv, TCGv_env, TCGv_i32); 666 667static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, 668 uint32_t data, gen_helper_ldst_stride *fn, 669 DisasContext *s, bool is_store) 670{ 671 TCGv_ptr dest, mask; 672 TCGv base, stride; 673 TCGv_i32 desc; 674 675 TCGLabel *over = gen_new_label(); 676 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 677 678 dest = tcg_temp_new_ptr(); 679 mask = tcg_temp_new_ptr(); 680 base = get_gpr(s, rs1, EXT_NONE); 681 stride = get_gpr(s, rs2, EXT_NONE); 682 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 683 684 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 685 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 686 687 fn(dest, mask, base, stride, cpu_env, desc); 688 689 tcg_temp_free_ptr(dest); 690 tcg_temp_free_ptr(mask); 691 692 if (!is_store) { 693 mark_vs_dirty(s); 694 } 695 696 gen_set_label(over); 697 return true; 698} 699 700static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 701{ 702 uint32_t data = 0; 703 gen_helper_ldst_stride *fn; 704 static gen_helper_ldst_stride * const fns[4] = { 705 gen_helper_vlse8_v, gen_helper_vlse16_v, 706 gen_helper_vlse32_v, gen_helper_vlse64_v 707 }; 708 709 fn = fns[eew]; 710 if (fn == NULL) { 711 return false; 712 } 713 714 data = FIELD_DP32(data, VDATA, VM, a->vm); 715 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 716 data = FIELD_DP32(data, VDATA, NF, a->nf); 717 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 718} 719 720static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 721{ 722 return require_rvv(s) && 723 vext_check_isa_ill(s) && 724 vext_check_load(s, a->rd, a->nf, a->vm, eew); 725} 726 727GEN_VEXT_TRANS(vlse8_v, MO_8, rnfvm, ld_stride_op, ld_stride_check) 728GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check) 729GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check) 730GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) 731 732static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 733{ 734 uint32_t data = 0; 735 gen_helper_ldst_stride *fn; 736 static gen_helper_ldst_stride * const fns[4] = { 737 /* masked stride store */ 738 gen_helper_vsse8_v, gen_helper_vsse16_v, 739 gen_helper_vsse32_v, gen_helper_vsse64_v 740 }; 741 742 data = FIELD_DP32(data, VDATA, VM, a->vm); 743 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 744 data = FIELD_DP32(data, VDATA, NF, a->nf); 745 fn = fns[eew]; 746 if (fn == NULL) { 747 return false; 748 } 749 750 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); 751} 752 753static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 754{ 755 return require_rvv(s) && 756 vext_check_isa_ill(s) && 757 vext_check_store(s, a->rd, a->nf, eew); 758} 759 760GEN_VEXT_TRANS(vsse8_v, MO_8, rnfvm, st_stride_op, st_stride_check) 761GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check) 762GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check) 763GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check) 764 765/* 766 *** index load and store 767 */ 768typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, 769 TCGv_ptr, TCGv_env, TCGv_i32); 770 771static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 772 uint32_t data, gen_helper_ldst_index *fn, 773 DisasContext *s, bool is_store) 774{ 775 TCGv_ptr dest, mask, index; 776 TCGv base; 777 TCGv_i32 desc; 778 779 TCGLabel *over = gen_new_label(); 780 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 781 782 dest = tcg_temp_new_ptr(); 783 mask = tcg_temp_new_ptr(); 784 index = tcg_temp_new_ptr(); 785 base = get_gpr(s, rs1, EXT_NONE); 786 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 787 788 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 789 tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); 790 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 791 792 fn(dest, mask, base, index, cpu_env, desc); 793 794 tcg_temp_free_ptr(dest); 795 tcg_temp_free_ptr(mask); 796 tcg_temp_free_ptr(index); 797 798 if (!is_store) { 799 mark_vs_dirty(s); 800 } 801 802 gen_set_label(over); 803 return true; 804} 805 806static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 807{ 808 uint32_t data = 0; 809 gen_helper_ldst_index *fn; 810 static gen_helper_ldst_index * const fns[4][4] = { 811 /* 812 * offset vector register group EEW = 8, 813 * data vector register group EEW = SEW 814 */ 815 { gen_helper_vlxei8_8_v, gen_helper_vlxei8_16_v, 816 gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v }, 817 /* 818 * offset vector register group EEW = 16, 819 * data vector register group EEW = SEW 820 */ 821 { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v, 822 gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v }, 823 /* 824 * offset vector register group EEW = 32, 825 * data vector register group EEW = SEW 826 */ 827 { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v, 828 gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v }, 829 /* 830 * offset vector register group EEW = 64, 831 * data vector register group EEW = SEW 832 */ 833 { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v, 834 gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v } 835 }; 836 837 fn = fns[eew][s->sew]; 838 839 data = FIELD_DP32(data, VDATA, VM, a->vm); 840 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 841 data = FIELD_DP32(data, VDATA, NF, a->nf); 842 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 843} 844 845static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 846{ 847 return require_rvv(s) && 848 vext_check_isa_ill(s) && 849 vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); 850} 851 852GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) 853GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check) 854GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check) 855GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check) 856 857static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 858{ 859 uint32_t data = 0; 860 gen_helper_ldst_index *fn; 861 static gen_helper_ldst_index * const fns[4][4] = { 862 /* 863 * offset vector register group EEW = 8, 864 * data vector register group EEW = SEW 865 */ 866 { gen_helper_vsxei8_8_v, gen_helper_vsxei8_16_v, 867 gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v }, 868 /* 869 * offset vector register group EEW = 16, 870 * data vector register group EEW = SEW 871 */ 872 { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v, 873 gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v }, 874 /* 875 * offset vector register group EEW = 32, 876 * data vector register group EEW = SEW 877 */ 878 { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v, 879 gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v }, 880 /* 881 * offset vector register group EEW = 64, 882 * data vector register group EEW = SEW 883 */ 884 { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v, 885 gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v } 886 }; 887 888 fn = fns[eew][s->sew]; 889 890 data = FIELD_DP32(data, VDATA, VM, a->vm); 891 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 892 data = FIELD_DP32(data, VDATA, NF, a->nf); 893 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); 894} 895 896static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 897{ 898 return require_rvv(s) && 899 vext_check_isa_ill(s) && 900 vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); 901} 902 903GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) 904GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check) 905GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check) 906GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check) 907 908/* 909 *** unit stride fault-only-first load 910 */ 911static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, 912 gen_helper_ldst_us *fn, DisasContext *s) 913{ 914 TCGv_ptr dest, mask; 915 TCGv base; 916 TCGv_i32 desc; 917 918 TCGLabel *over = gen_new_label(); 919 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 920 921 dest = tcg_temp_new_ptr(); 922 mask = tcg_temp_new_ptr(); 923 base = get_gpr(s, rs1, EXT_NONE); 924 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 925 926 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 927 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 928 929 fn(dest, mask, base, cpu_env, desc); 930 931 tcg_temp_free_ptr(dest); 932 tcg_temp_free_ptr(mask); 933 mark_vs_dirty(s); 934 gen_set_label(over); 935 return true; 936} 937 938static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t seq) 939{ 940 uint32_t data = 0; 941 gen_helper_ldst_us *fn; 942 static gen_helper_ldst_us * const fns[7][4] = { 943 { gen_helper_vlbff_v_b, gen_helper_vlbff_v_h, 944 gen_helper_vlbff_v_w, gen_helper_vlbff_v_d }, 945 { NULL, gen_helper_vlhff_v_h, 946 gen_helper_vlhff_v_w, gen_helper_vlhff_v_d }, 947 { NULL, NULL, 948 gen_helper_vlwff_v_w, gen_helper_vlwff_v_d }, 949 { gen_helper_vleff_v_b, gen_helper_vleff_v_h, 950 gen_helper_vleff_v_w, gen_helper_vleff_v_d }, 951 { gen_helper_vlbuff_v_b, gen_helper_vlbuff_v_h, 952 gen_helper_vlbuff_v_w, gen_helper_vlbuff_v_d }, 953 { NULL, gen_helper_vlhuff_v_h, 954 gen_helper_vlhuff_v_w, gen_helper_vlhuff_v_d }, 955 { NULL, NULL, 956 gen_helper_vlwuff_v_w, gen_helper_vlwuff_v_d } 957 }; 958 959 fn = fns[seq][s->sew]; 960 if (fn == NULL) { 961 return false; 962 } 963 964 data = FIELD_DP32(data, VDATA, VM, a->vm); 965 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 966 data = FIELD_DP32(data, VDATA, NF, a->nf); 967 return ldff_trans(a->rd, a->rs1, data, fn, s); 968} 969 970GEN_VEXT_TRANS(vlbff_v, 0, r2nfvm, ldff_op, ld_us_check) 971GEN_VEXT_TRANS(vlhff_v, 1, r2nfvm, ldff_op, ld_us_check) 972GEN_VEXT_TRANS(vlwff_v, 2, r2nfvm, ldff_op, ld_us_check) 973GEN_VEXT_TRANS(vleff_v, 3, r2nfvm, ldff_op, ld_us_check) 974GEN_VEXT_TRANS(vlbuff_v, 4, r2nfvm, ldff_op, ld_us_check) 975GEN_VEXT_TRANS(vlhuff_v, 5, r2nfvm, ldff_op, ld_us_check) 976GEN_VEXT_TRANS(vlwuff_v, 6, r2nfvm, ldff_op, ld_us_check) 977 978/* 979 *** Vector Integer Arithmetic Instructions 980 */ 981#define MAXSZ(s) (s->vlen >> (3 - s->lmul)) 982 983static bool opivv_check(DisasContext *s, arg_rmrr *a) 984{ 985 return require_rvv(s) && 986 vext_check_isa_ill(s) && 987 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 988} 989 990typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 991 uint32_t, uint32_t, uint32_t); 992 993static inline bool 994do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 995 gen_helper_gvec_4_ptr *fn) 996{ 997 TCGLabel *over = gen_new_label(); 998 if (!opivv_check(s, a)) { 999 return false; 1000 } 1001 1002 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1003 1004 if (a->vm && s->vl_eq_vlmax) { 1005 gvec_fn(s->sew, vreg_ofs(s, a->rd), 1006 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 1007 MAXSZ(s), MAXSZ(s)); 1008 } else { 1009 uint32_t data = 0; 1010 1011 data = FIELD_DP32(data, VDATA, VM, a->vm); 1012 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1013 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1014 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 1015 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1016 } 1017 mark_vs_dirty(s); 1018 gen_set_label(over); 1019 return true; 1020} 1021 1022/* OPIVV with GVEC IR */ 1023#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 1024static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1025{ \ 1026 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1027 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1028 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1029 }; \ 1030 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1031} 1032 1033GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 1034GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 1035 1036typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 1037 TCGv_env, TCGv_i32); 1038 1039static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 1040 gen_helper_opivx *fn, DisasContext *s) 1041{ 1042 TCGv_ptr dest, src2, mask; 1043 TCGv src1; 1044 TCGv_i32 desc; 1045 uint32_t data = 0; 1046 1047 TCGLabel *over = gen_new_label(); 1048 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1049 1050 dest = tcg_temp_new_ptr(); 1051 mask = tcg_temp_new_ptr(); 1052 src2 = tcg_temp_new_ptr(); 1053 src1 = get_gpr(s, rs1, EXT_NONE); 1054 1055 data = FIELD_DP32(data, VDATA, VM, vm); 1056 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1057 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1058 1059 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1060 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1061 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1062 1063 fn(dest, mask, src1, src2, cpu_env, desc); 1064 1065 tcg_temp_free_ptr(dest); 1066 tcg_temp_free_ptr(mask); 1067 tcg_temp_free_ptr(src2); 1068 mark_vs_dirty(s); 1069 gen_set_label(over); 1070 return true; 1071} 1072 1073static bool opivx_check(DisasContext *s, arg_rmrr *a) 1074{ 1075 return require_rvv(s) && 1076 vext_check_isa_ill(s) && 1077 vext_check_ss(s, a->rd, a->rs2, a->vm); 1078} 1079 1080typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 1081 uint32_t, uint32_t); 1082 1083static inline bool 1084do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 1085 gen_helper_opivx *fn) 1086{ 1087 if (!opivx_check(s, a)) { 1088 return false; 1089 } 1090 1091 if (a->vm && s->vl_eq_vlmax) { 1092 TCGv_i64 src1 = tcg_temp_new_i64(); 1093 1094 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 1095 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1096 src1, MAXSZ(s), MAXSZ(s)); 1097 1098 tcg_temp_free_i64(src1); 1099 mark_vs_dirty(s); 1100 return true; 1101 } 1102 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1103} 1104 1105/* OPIVX with GVEC IR */ 1106#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 1107static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1108{ \ 1109 static gen_helper_opivx * const fns[4] = { \ 1110 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1111 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1112 }; \ 1113 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1114} 1115 1116GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 1117GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 1118 1119static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1120{ 1121 tcg_gen_vec_sub8_i64(d, b, a); 1122} 1123 1124static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1125{ 1126 tcg_gen_vec_sub16_i64(d, b, a); 1127} 1128 1129static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 1130{ 1131 tcg_gen_sub_i32(ret, arg2, arg1); 1132} 1133 1134static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1135{ 1136 tcg_gen_sub_i64(ret, arg2, arg1); 1137} 1138 1139static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 1140{ 1141 tcg_gen_sub_vec(vece, r, b, a); 1142} 1143 1144static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 1145 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 1146{ 1147 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 1148 static const GVecGen2s rsub_op[4] = { 1149 { .fni8 = gen_vec_rsub8_i64, 1150 .fniv = gen_rsub_vec, 1151 .fno = gen_helper_vec_rsubs8, 1152 .opt_opc = vecop_list, 1153 .vece = MO_8 }, 1154 { .fni8 = gen_vec_rsub16_i64, 1155 .fniv = gen_rsub_vec, 1156 .fno = gen_helper_vec_rsubs16, 1157 .opt_opc = vecop_list, 1158 .vece = MO_16 }, 1159 { .fni4 = gen_rsub_i32, 1160 .fniv = gen_rsub_vec, 1161 .fno = gen_helper_vec_rsubs32, 1162 .opt_opc = vecop_list, 1163 .vece = MO_32 }, 1164 { .fni8 = gen_rsub_i64, 1165 .fniv = gen_rsub_vec, 1166 .fno = gen_helper_vec_rsubs64, 1167 .opt_opc = vecop_list, 1168 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 1169 .vece = MO_64 }, 1170 }; 1171 1172 tcg_debug_assert(vece <= MO_64); 1173 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 1174} 1175 1176GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 1177 1178typedef enum { 1179 IMM_ZX, /* Zero-extended */ 1180 IMM_SX, /* Sign-extended */ 1181 IMM_TRUNC_SEW, /* Truncate to log(SEW) bits */ 1182 IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */ 1183} imm_mode_t; 1184 1185static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode) 1186{ 1187 switch (imm_mode) { 1188 case IMM_ZX: 1189 return extract64(imm, 0, 5); 1190 case IMM_SX: 1191 return sextract64(imm, 0, 5); 1192 case IMM_TRUNC_SEW: 1193 return extract64(imm, 0, s->sew + 3); 1194 case IMM_TRUNC_2SEW: 1195 return extract64(imm, 0, s->sew + 4); 1196 default: 1197 g_assert_not_reached(); 1198 } 1199} 1200 1201static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 1202 gen_helper_opivx *fn, DisasContext *s, 1203 imm_mode_t imm_mode) 1204{ 1205 TCGv_ptr dest, src2, mask; 1206 TCGv src1; 1207 TCGv_i32 desc; 1208 uint32_t data = 0; 1209 1210 TCGLabel *over = gen_new_label(); 1211 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1212 1213 dest = tcg_temp_new_ptr(); 1214 mask = tcg_temp_new_ptr(); 1215 src2 = tcg_temp_new_ptr(); 1216 src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode)); 1217 1218 data = FIELD_DP32(data, VDATA, VM, vm); 1219 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1220 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1221 1222 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1223 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1224 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1225 1226 fn(dest, mask, src1, src2, cpu_env, desc); 1227 1228 tcg_temp_free_ptr(dest); 1229 tcg_temp_free_ptr(mask); 1230 tcg_temp_free_ptr(src2); 1231 mark_vs_dirty(s); 1232 gen_set_label(over); 1233 return true; 1234} 1235 1236typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1237 uint32_t, uint32_t); 1238 1239static inline bool 1240do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1241 gen_helper_opivx *fn, imm_mode_t imm_mode) 1242{ 1243 if (!opivx_check(s, a)) { 1244 return false; 1245 } 1246 1247 if (a->vm && s->vl_eq_vlmax) { 1248 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1249 extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); 1250 mark_vs_dirty(s); 1251 return true; 1252 } 1253 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode); 1254} 1255 1256/* OPIVI with GVEC IR */ 1257#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \ 1258static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1259{ \ 1260 static gen_helper_opivx * const fns[4] = { \ 1261 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1262 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1263 }; \ 1264 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1265 fns[s->sew], IMM_MODE); \ 1266} 1267 1268GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi) 1269 1270static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1271 int64_t c, uint32_t oprsz, uint32_t maxsz) 1272{ 1273 TCGv_i64 tmp = tcg_constant_i64(c); 1274 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1275} 1276 1277GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi) 1278 1279/* Vector Widening Integer Add/Subtract */ 1280 1281/* OPIVV with WIDEN */ 1282static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1283{ 1284 return require_rvv(s) && 1285 vext_check_isa_ill(s) && 1286 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 1287} 1288 1289static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1290 gen_helper_gvec_4_ptr *fn, 1291 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1292{ 1293 if (checkfn(s, a)) { 1294 uint32_t data = 0; 1295 TCGLabel *over = gen_new_label(); 1296 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1297 1298 data = FIELD_DP32(data, VDATA, VM, a->vm); 1299 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1300 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1301 vreg_ofs(s, a->rs1), 1302 vreg_ofs(s, a->rs2), 1303 cpu_env, s->vlen / 8, s->vlen / 8, 1304 data, fn); 1305 mark_vs_dirty(s); 1306 gen_set_label(over); 1307 return true; 1308 } 1309 return false; 1310} 1311 1312#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1313static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1314{ \ 1315 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1316 gen_helper_##NAME##_b, \ 1317 gen_helper_##NAME##_h, \ 1318 gen_helper_##NAME##_w \ 1319 }; \ 1320 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1321} 1322 1323GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1324GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1325GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1326GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1327 1328/* OPIVX with WIDEN */ 1329static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1330{ 1331 return require_rvv(s) && 1332 vext_check_isa_ill(s) && 1333 vext_check_ds(s, a->rd, a->rs2, a->vm); 1334} 1335 1336static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, 1337 gen_helper_opivx *fn) 1338{ 1339 if (opivx_widen_check(s, a)) { 1340 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1341 } 1342 return false; 1343} 1344 1345#define GEN_OPIVX_WIDEN_TRANS(NAME) \ 1346static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1347{ \ 1348 static gen_helper_opivx * const fns[3] = { \ 1349 gen_helper_##NAME##_b, \ 1350 gen_helper_##NAME##_h, \ 1351 gen_helper_##NAME##_w \ 1352 }; \ 1353 return do_opivx_widen(s, a, fns[s->sew]); \ 1354} 1355 1356GEN_OPIVX_WIDEN_TRANS(vwaddu_vx) 1357GEN_OPIVX_WIDEN_TRANS(vwadd_vx) 1358GEN_OPIVX_WIDEN_TRANS(vwsubu_vx) 1359GEN_OPIVX_WIDEN_TRANS(vwsub_vx) 1360 1361/* WIDEN OPIVV with WIDEN */ 1362static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1363{ 1364 return require_rvv(s) && 1365 vext_check_isa_ill(s) && 1366 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 1367} 1368 1369static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1370 gen_helper_gvec_4_ptr *fn) 1371{ 1372 if (opiwv_widen_check(s, a)) { 1373 uint32_t data = 0; 1374 TCGLabel *over = gen_new_label(); 1375 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1376 1377 data = FIELD_DP32(data, VDATA, VM, a->vm); 1378 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1379 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1380 vreg_ofs(s, a->rs1), 1381 vreg_ofs(s, a->rs2), 1382 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1383 mark_vs_dirty(s); 1384 gen_set_label(over); 1385 return true; 1386 } 1387 return false; 1388} 1389 1390#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1391static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1392{ \ 1393 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1394 gen_helper_##NAME##_b, \ 1395 gen_helper_##NAME##_h, \ 1396 gen_helper_##NAME##_w \ 1397 }; \ 1398 return do_opiwv_widen(s, a, fns[s->sew]); \ 1399} 1400 1401GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1402GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1403GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1404GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1405 1406/* WIDEN OPIVX with WIDEN */ 1407static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1408{ 1409 return require_rvv(s) && 1410 vext_check_isa_ill(s) && 1411 vext_check_dd(s, a->rd, a->rs2, a->vm); 1412} 1413 1414static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1415 gen_helper_opivx *fn) 1416{ 1417 if (opiwx_widen_check(s, a)) { 1418 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1419 } 1420 return false; 1421} 1422 1423#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1424static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1425{ \ 1426 static gen_helper_opivx * const fns[3] = { \ 1427 gen_helper_##NAME##_b, \ 1428 gen_helper_##NAME##_h, \ 1429 gen_helper_##NAME##_w \ 1430 }; \ 1431 return do_opiwx_widen(s, a, fns[s->sew]); \ 1432} 1433 1434GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1435GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1436GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1437GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1438 1439/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1440/* OPIVV without GVEC IR */ 1441#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1442static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1443{ \ 1444 if (CHECK(s, a)) { \ 1445 uint32_t data = 0; \ 1446 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1447 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1448 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1449 }; \ 1450 TCGLabel *over = gen_new_label(); \ 1451 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1452 \ 1453 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1454 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1455 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1456 vreg_ofs(s, a->rs1), \ 1457 vreg_ofs(s, a->rs2), cpu_env, \ 1458 s->vlen / 8, s->vlen / 8, data, \ 1459 fns[s->sew]); \ 1460 mark_vs_dirty(s); \ 1461 gen_set_label(over); \ 1462 return true; \ 1463 } \ 1464 return false; \ 1465} 1466 1467/* 1468 * For vadc and vsbc, an illegal instruction exception is raised if the 1469 * destination vector register is v0 and LMUL > 1. (Section 12.3) 1470 */ 1471static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1472{ 1473 return require_rvv(s) && 1474 vext_check_isa_ill(s) && 1475 (a->rd != 0) && 1476 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1477} 1478 1479GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1480GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1481 1482/* 1483 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1484 * destination vector register overlaps a source vector register group. 1485 */ 1486static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1487{ 1488 return require_rvv(s) && 1489 vext_check_isa_ill(s) && 1490 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1491} 1492 1493GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1494GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1495 1496static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1497{ 1498 return require_rvv(s) && 1499 vext_check_isa_ill(s) && 1500 (a->rd != 0) && 1501 vext_check_ss(s, a->rd, a->rs2, a->vm); 1502} 1503 1504/* OPIVX without GVEC IR */ 1505#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1506static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1507{ \ 1508 if (CHECK(s, a)) { \ 1509 static gen_helper_opivx * const fns[4] = { \ 1510 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1511 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1512 }; \ 1513 \ 1514 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1515 } \ 1516 return false; \ 1517} 1518 1519GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1520GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1521 1522static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1523{ 1524 return require_rvv(s) && 1525 vext_check_isa_ill(s) && 1526 vext_check_ms(s, a->rd, a->rs2); 1527} 1528 1529GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1530GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1531 1532/* OPIVI without GVEC IR */ 1533#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK) \ 1534static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1535{ \ 1536 if (CHECK(s, a)) { \ 1537 static gen_helper_opivx * const fns[4] = { \ 1538 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1539 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1540 }; \ 1541 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1542 fns[s->sew], s, IMM_MODE); \ 1543 } \ 1544 return false; \ 1545} 1546 1547GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check) 1548GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check) 1549 1550/* Vector Bitwise Logical Instructions */ 1551GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1552GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1553GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1554GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1555GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1556GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1557GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi) 1558GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx, ori) 1559GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori) 1560 1561/* Vector Single-Width Bit Shift Instructions */ 1562GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1563GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1564GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1565 1566typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1567 uint32_t, uint32_t); 1568 1569static inline bool 1570do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1571 gen_helper_opivx *fn) 1572{ 1573 if (!opivx_check(s, a)) { 1574 return false; 1575 } 1576 1577 if (a->vm && s->vl_eq_vlmax) { 1578 TCGv_i32 src1 = tcg_temp_new_i32(); 1579 1580 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1581 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1582 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1583 src1, MAXSZ(s), MAXSZ(s)); 1584 1585 tcg_temp_free_i32(src1); 1586 mark_vs_dirty(s); 1587 return true; 1588 } 1589 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1590} 1591 1592#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1593static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1594{ \ 1595 static gen_helper_opivx * const fns[4] = { \ 1596 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1597 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1598 }; \ 1599 \ 1600 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1601} 1602 1603GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1604GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1605GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1606 1607GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_ZX, vsll_vx, shli) 1608GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_ZX, vsrl_vx, shri) 1609GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_ZX, vsra_vx, sari) 1610 1611/* Vector Narrowing Integer Right Shift Instructions */ 1612static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) 1613{ 1614 return require_rvv(s) && 1615 vext_check_isa_ill(s) && 1616 vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm); 1617} 1618 1619/* OPIVV with NARROW */ 1620#define GEN_OPIVV_NARROW_TRANS(NAME) \ 1621static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1622{ \ 1623 if (opivv_narrow_check(s, a)) { \ 1624 uint32_t data = 0; \ 1625 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1626 gen_helper_##NAME##_b, \ 1627 gen_helper_##NAME##_h, \ 1628 gen_helper_##NAME##_w, \ 1629 }; \ 1630 TCGLabel *over = gen_new_label(); \ 1631 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1632 \ 1633 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1634 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1635 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1636 vreg_ofs(s, a->rs1), \ 1637 vreg_ofs(s, a->rs2), cpu_env, \ 1638 s->vlen / 8, s->vlen / 8, data, \ 1639 fns[s->sew]); \ 1640 mark_vs_dirty(s); \ 1641 gen_set_label(over); \ 1642 return true; \ 1643 } \ 1644 return false; \ 1645} 1646GEN_OPIVV_NARROW_TRANS(vnsra_vv) 1647GEN_OPIVV_NARROW_TRANS(vnsrl_vv) 1648 1649static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) 1650{ 1651 return require_rvv(s) && 1652 vext_check_isa_ill(s) && 1653 vext_check_sd(s, a->rd, a->rs2, a->vm); 1654} 1655 1656/* OPIVX with NARROW */ 1657#define GEN_OPIVX_NARROW_TRANS(NAME) \ 1658static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1659{ \ 1660 if (opivx_narrow_check(s, a)) { \ 1661 static gen_helper_opivx * const fns[3] = { \ 1662 gen_helper_##NAME##_b, \ 1663 gen_helper_##NAME##_h, \ 1664 gen_helper_##NAME##_w, \ 1665 }; \ 1666 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1667 } \ 1668 return false; \ 1669} 1670 1671GEN_OPIVX_NARROW_TRANS(vnsra_vx) 1672GEN_OPIVX_NARROW_TRANS(vnsrl_vx) 1673 1674/* OPIVI with NARROW */ 1675#define GEN_OPIVI_NARROW_TRANS(NAME, IMM_MODE, OPIVX) \ 1676static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1677{ \ 1678 if (opivx_narrow_check(s, a)) { \ 1679 static gen_helper_opivx * const fns[3] = { \ 1680 gen_helper_##OPIVX##_b, \ 1681 gen_helper_##OPIVX##_h, \ 1682 gen_helper_##OPIVX##_w, \ 1683 }; \ 1684 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1685 fns[s->sew], s, IMM_MODE); \ 1686 } \ 1687 return false; \ 1688} 1689 1690GEN_OPIVI_NARROW_TRANS(vnsra_vi, IMM_ZX, vnsra_vx) 1691GEN_OPIVI_NARROW_TRANS(vnsrl_vi, IMM_ZX, vnsrl_vx) 1692 1693/* Vector Integer Comparison Instructions */ 1694/* 1695 * For all comparison instructions, an illegal instruction exception is raised 1696 * if the destination vector register overlaps a source vector register group 1697 * and LMUL > 1. 1698 */ 1699static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1700{ 1701 return require_rvv(s) && 1702 vext_check_isa_ill(s) && 1703 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1704} 1705 1706GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1707GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1708GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1709GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1710GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1711GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1712 1713static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1714{ 1715 return require_rvv(s) && 1716 vext_check_isa_ill(s) && 1717 vext_check_ms(s, a->rd, a->rs2); 1718} 1719 1720GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1721GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1722GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1723GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1724GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1725GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1726GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1727GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1728 1729GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check) 1730GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check) 1731GEN_OPIVI_TRANS(vmsleu_vi, IMM_ZX, vmsleu_vx, opivx_cmp_check) 1732GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check) 1733GEN_OPIVI_TRANS(vmsgtu_vi, IMM_ZX, vmsgtu_vx, opivx_cmp_check) 1734GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check) 1735 1736/* Vector Integer Min/Max Instructions */ 1737GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1738GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1739GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1740GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1741GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1742GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1743GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1744GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1745 1746/* Vector Single-Width Integer Multiply Instructions */ 1747GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1748GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1749GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1750GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1751GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1752GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1753GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1754GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1755 1756/* Vector Integer Divide Instructions */ 1757GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1758GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1759GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1760GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1761GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1762GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1763GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1764GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1765 1766/* Vector Widening Integer Multiply Instructions */ 1767GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1768GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1769GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1770GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1771GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1772GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1773 1774/* Vector Single-Width Integer Multiply-Add Instructions */ 1775GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1776GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1777GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1778GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1779GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1780GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1781GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1782GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1783 1784/* Vector Widening Integer Multiply-Add Instructions */ 1785GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1786GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1787GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1788GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1789GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1790GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1791GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1792 1793/* Vector Integer Merge and Move Instructions */ 1794static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1795{ 1796 if (require_rvv(s) && 1797 vext_check_isa_ill(s) && 1798 /* vmv.v.v has rs2 = 0 and vm = 1 */ 1799 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 1800 if (s->vl_eq_vlmax) { 1801 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1802 vreg_ofs(s, a->rs1), 1803 MAXSZ(s), MAXSZ(s)); 1804 } else { 1805 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1806 static gen_helper_gvec_2_ptr * const fns[4] = { 1807 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1808 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1809 }; 1810 TCGLabel *over = gen_new_label(); 1811 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1812 1813 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1814 cpu_env, s->vlen / 8, s->vlen / 8, data, 1815 fns[s->sew]); 1816 gen_set_label(over); 1817 } 1818 mark_vs_dirty(s); 1819 return true; 1820 } 1821 return false; 1822} 1823 1824typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1825static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1826{ 1827 if (require_rvv(s) && 1828 vext_check_isa_ill(s) && 1829 /* vmv.v.x has rs2 = 0 and vm = 1 */ 1830 vext_check_ss(s, a->rd, 0, 1)) { 1831 TCGv s1; 1832 TCGLabel *over = gen_new_label(); 1833 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1834 1835 s1 = get_gpr(s, a->rs1, EXT_SIGN); 1836 1837 if (s->vl_eq_vlmax) { 1838 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 1839 MAXSZ(s), MAXSZ(s), s1); 1840 } else { 1841 TCGv_i32 desc; 1842 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 1843 TCGv_ptr dest = tcg_temp_new_ptr(); 1844 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1845 static gen_helper_vmv_vx * const fns[4] = { 1846 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1847 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1848 }; 1849 1850 tcg_gen_ext_tl_i64(s1_i64, s1); 1851 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1852 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1853 fns[s->sew](dest, s1_i64, cpu_env, desc); 1854 1855 tcg_temp_free_ptr(dest); 1856 tcg_temp_free_i64(s1_i64); 1857 } 1858 1859 mark_vs_dirty(s); 1860 gen_set_label(over); 1861 return true; 1862 } 1863 return false; 1864} 1865 1866static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 1867{ 1868 if (require_rvv(s) && 1869 vext_check_isa_ill(s) && 1870 /* vmv.v.i has rs2 = 0 and vm = 1 */ 1871 vext_check_ss(s, a->rd, 0, 1)) { 1872 int64_t simm = sextract64(a->rs1, 0, 5); 1873 if (s->vl_eq_vlmax) { 1874 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 1875 MAXSZ(s), MAXSZ(s), simm); 1876 mark_vs_dirty(s); 1877 } else { 1878 TCGv_i32 desc; 1879 TCGv_i64 s1; 1880 TCGv_ptr dest; 1881 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1882 static gen_helper_vmv_vx * const fns[4] = { 1883 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1884 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1885 }; 1886 TCGLabel *over = gen_new_label(); 1887 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1888 1889 s1 = tcg_constant_i64(simm); 1890 dest = tcg_temp_new_ptr(); 1891 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1892 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1893 fns[s->sew](dest, s1, cpu_env, desc); 1894 1895 tcg_temp_free_ptr(dest); 1896 mark_vs_dirty(s); 1897 gen_set_label(over); 1898 } 1899 return true; 1900 } 1901 return false; 1902} 1903 1904GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 1905GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 1906GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 1907 1908/* 1909 *** Vector Fixed-Point Arithmetic Instructions 1910 */ 1911 1912/* Vector Single-Width Saturating Add and Subtract */ 1913GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 1914GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 1915GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 1916GEN_OPIVV_TRANS(vssub_vv, opivv_check) 1917GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 1918GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 1919GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 1920GEN_OPIVX_TRANS(vssub_vx, opivx_check) 1921GEN_OPIVI_TRANS(vsaddu_vi, IMM_ZX, vsaddu_vx, opivx_check) 1922GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 1923 1924/* Vector Single-Width Averaging Add and Subtract */ 1925GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 1926GEN_OPIVV_TRANS(vasub_vv, opivv_check) 1927GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 1928GEN_OPIVX_TRANS(vasub_vx, opivx_check) 1929GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) 1930 1931/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 1932GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 1933GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 1934 1935/* Vector Widening Saturating Scaled Multiply-Add */ 1936GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) 1937GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) 1938GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) 1939GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) 1940GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) 1941GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) 1942GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) 1943 1944/* Vector Single-Width Scaling Shift Instructions */ 1945GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 1946GEN_OPIVV_TRANS(vssra_vv, opivv_check) 1947GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 1948GEN_OPIVX_TRANS(vssra_vx, opivx_check) 1949GEN_OPIVI_TRANS(vssrl_vi, IMM_ZX, vssrl_vx, opivx_check) 1950GEN_OPIVI_TRANS(vssra_vi, IMM_SX, vssra_vx, opivx_check) 1951 1952/* Vector Narrowing Fixed-Point Clip Instructions */ 1953GEN_OPIVV_NARROW_TRANS(vnclipu_vv) 1954GEN_OPIVV_NARROW_TRANS(vnclip_vv) 1955GEN_OPIVX_NARROW_TRANS(vnclipu_vx) 1956GEN_OPIVX_NARROW_TRANS(vnclip_vx) 1957GEN_OPIVI_NARROW_TRANS(vnclipu_vi, IMM_ZX, vnclipu_vx) 1958GEN_OPIVI_NARROW_TRANS(vnclip_vi, IMM_ZX, vnclip_vx) 1959 1960/* 1961 *** Vector Float Point Arithmetic Instructions 1962 */ 1963 1964/* 1965 * As RVF-only cpus always have values NaN-boxed to 64-bits, 1966 * RVF and RVD can be treated equally. 1967 * We don't have to deal with the cases of: SEW > FLEN. 1968 * 1969 * If SEW < FLEN, check whether input fp register is a valid 1970 * NaN-boxed value, in which case the least-significant SEW bits 1971 * of the f regsiter are used, else the canonical NaN value is used. 1972 */ 1973static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 1974{ 1975 switch (s->sew) { 1976 case 1: 1977 gen_check_nanbox_h(out, in); 1978 break; 1979 case 2: 1980 gen_check_nanbox_s(out, in); 1981 break; 1982 case 3: 1983 tcg_gen_mov_i64(out, in); 1984 break; 1985 default: 1986 g_assert_not_reached(); 1987 } 1988} 1989 1990/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 1991 1992/* 1993 * If the current SEW does not correspond to a supported IEEE floating-point 1994 * type, an illegal instruction exception is raised. 1995 */ 1996static bool opfvv_check(DisasContext *s, arg_rmrr *a) 1997{ 1998 return require_rvv(s) && 1999 require_rvf(s) && 2000 vext_check_isa_ill(s) && 2001 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2002} 2003 2004/* OPFVV without GVEC IR */ 2005#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2006static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2007{ \ 2008 if (CHECK(s, a)) { \ 2009 uint32_t data = 0; \ 2010 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2011 gen_helper_##NAME##_h, \ 2012 gen_helper_##NAME##_w, \ 2013 gen_helper_##NAME##_d, \ 2014 }; \ 2015 TCGLabel *over = gen_new_label(); \ 2016 gen_set_rm(s, 7); \ 2017 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2018 \ 2019 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2020 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2021 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2022 vreg_ofs(s, a->rs1), \ 2023 vreg_ofs(s, a->rs2), cpu_env, \ 2024 s->vlen / 8, s->vlen / 8, data, \ 2025 fns[s->sew - 1]); \ 2026 mark_vs_dirty(s); \ 2027 gen_set_label(over); \ 2028 return true; \ 2029 } \ 2030 return false; \ 2031} 2032GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2033GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2034 2035typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2036 TCGv_env, TCGv_i32); 2037 2038static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2039 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2040{ 2041 TCGv_ptr dest, src2, mask; 2042 TCGv_i32 desc; 2043 TCGv_i64 t1; 2044 2045 TCGLabel *over = gen_new_label(); 2046 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2047 2048 dest = tcg_temp_new_ptr(); 2049 mask = tcg_temp_new_ptr(); 2050 src2 = tcg_temp_new_ptr(); 2051 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2052 2053 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 2054 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 2055 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2056 2057 /* NaN-box f[rs1] */ 2058 t1 = tcg_temp_new_i64(); 2059 do_nanbox(s, t1, cpu_fpr[rs1]); 2060 2061 fn(dest, mask, t1, src2, cpu_env, desc); 2062 2063 tcg_temp_free_ptr(dest); 2064 tcg_temp_free_ptr(mask); 2065 tcg_temp_free_ptr(src2); 2066 tcg_temp_free_i64(t1); 2067 mark_vs_dirty(s); 2068 gen_set_label(over); 2069 return true; 2070} 2071 2072/* 2073 * If the current SEW does not correspond to a supported IEEE floating-point 2074 * type, an illegal instruction exception is raised 2075 */ 2076static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2077{ 2078 return require_rvv(s) && 2079 require_rvf(s) && 2080 vext_check_isa_ill(s) && 2081 vext_check_ss(s, a->rd, a->rs2, a->vm); 2082} 2083 2084/* OPFVF without GVEC IR */ 2085#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2086static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2087{ \ 2088 if (CHECK(s, a)) { \ 2089 uint32_t data = 0; \ 2090 static gen_helper_opfvf *const fns[3] = { \ 2091 gen_helper_##NAME##_h, \ 2092 gen_helper_##NAME##_w, \ 2093 gen_helper_##NAME##_d, \ 2094 }; \ 2095 gen_set_rm(s, 7); \ 2096 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2097 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2098 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2099 fns[s->sew - 1], s); \ 2100 } \ 2101 return false; \ 2102} 2103 2104GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2105GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2106GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2107 2108/* Vector Widening Floating-Point Add/Subtract Instructions */ 2109static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2110{ 2111 return require_rvv(s) && 2112 require_rvf(s) && 2113 vext_check_isa_ill(s) && 2114 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2115} 2116 2117/* OPFVV with WIDEN */ 2118#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2119static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2120{ \ 2121 if (CHECK(s, a)) { \ 2122 uint32_t data = 0; \ 2123 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2124 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2125 }; \ 2126 TCGLabel *over = gen_new_label(); \ 2127 gen_set_rm(s, 7); \ 2128 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2129 \ 2130 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2131 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2132 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2133 vreg_ofs(s, a->rs1), \ 2134 vreg_ofs(s, a->rs2), cpu_env, \ 2135 s->vlen / 8, s->vlen / 8, data, \ 2136 fns[s->sew - 1]); \ 2137 mark_vs_dirty(s); \ 2138 gen_set_label(over); \ 2139 return true; \ 2140 } \ 2141 return false; \ 2142} 2143 2144GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2145GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2146 2147static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2148{ 2149 return require_rvv(s) && 2150 require_rvf(s) && 2151 vext_check_isa_ill(s) && 2152 vext_check_ds(s, a->rd, a->rs2, a->vm); 2153} 2154 2155/* OPFVF with WIDEN */ 2156#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2157static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2158{ \ 2159 if (opfvf_widen_check(s, a)) { \ 2160 uint32_t data = 0; \ 2161 static gen_helper_opfvf *const fns[2] = { \ 2162 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2163 }; \ 2164 gen_set_rm(s, 7); \ 2165 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2166 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2167 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2168 fns[s->sew - 1], s); \ 2169 } \ 2170 return false; \ 2171} 2172 2173GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2174GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2175 2176static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2177{ 2178 return require_rvv(s) && 2179 require_rvf(s) && 2180 vext_check_isa_ill(s) && 2181 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2182} 2183 2184/* WIDEN OPFVV with WIDEN */ 2185#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2186static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2187{ \ 2188 if (opfwv_widen_check(s, a)) { \ 2189 uint32_t data = 0; \ 2190 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2191 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2192 }; \ 2193 TCGLabel *over = gen_new_label(); \ 2194 gen_set_rm(s, 7); \ 2195 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2196 \ 2197 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2198 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2199 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2200 vreg_ofs(s, a->rs1), \ 2201 vreg_ofs(s, a->rs2), cpu_env, \ 2202 s->vlen / 8, s->vlen / 8, data, \ 2203 fns[s->sew - 1]); \ 2204 mark_vs_dirty(s); \ 2205 gen_set_label(over); \ 2206 return true; \ 2207 } \ 2208 return false; \ 2209} 2210 2211GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2212GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2213 2214static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2215{ 2216 return require_rvv(s) && 2217 require_rvf(s) && 2218 vext_check_isa_ill(s) && 2219 vext_check_dd(s, a->rd, a->rs2, a->vm); 2220} 2221 2222/* WIDEN OPFVF with WIDEN */ 2223#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2224static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2225{ \ 2226 if (opfwf_widen_check(s, a)) { \ 2227 uint32_t data = 0; \ 2228 static gen_helper_opfvf *const fns[2] = { \ 2229 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2230 }; \ 2231 gen_set_rm(s, 7); \ 2232 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2233 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2234 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2235 fns[s->sew - 1], s); \ 2236 } \ 2237 return false; \ 2238} 2239 2240GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2241GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2242 2243/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2244GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2245GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2246GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2247GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2248GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2249 2250/* Vector Widening Floating-Point Multiply */ 2251GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2252GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2253 2254/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2255GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2256GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2257GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2258GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2259GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2260GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2261GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2262GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2263GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2264GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2265GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2266GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2267GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2268GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2269GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2270GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2271 2272/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2273GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2274GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2275GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2276GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2277GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2278GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2279GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2280GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2281 2282/* Vector Floating-Point Square-Root Instruction */ 2283 2284/* 2285 * If the current SEW does not correspond to a supported IEEE floating-point 2286 * type, an illegal instruction exception is raised 2287 */ 2288static bool opfv_check(DisasContext *s, arg_rmr *a) 2289{ 2290 return require_rvv(s) && 2291 require_rvf(s) && 2292 vext_check_isa_ill(s) && 2293 /* OPFV instructions ignore vs1 check */ 2294 vext_check_ss(s, a->rd, a->rs2, a->vm); 2295} 2296 2297#define GEN_OPFV_TRANS(NAME, CHECK) \ 2298static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2299{ \ 2300 if (CHECK(s, a)) { \ 2301 uint32_t data = 0; \ 2302 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2303 gen_helper_##NAME##_h, \ 2304 gen_helper_##NAME##_w, \ 2305 gen_helper_##NAME##_d, \ 2306 }; \ 2307 TCGLabel *over = gen_new_label(); \ 2308 gen_set_rm(s, 7); \ 2309 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2310 \ 2311 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2312 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2313 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2314 vreg_ofs(s, a->rs2), cpu_env, \ 2315 s->vlen / 8, s->vlen / 8, data, \ 2316 fns[s->sew - 1]); \ 2317 mark_vs_dirty(s); \ 2318 gen_set_label(over); \ 2319 return true; \ 2320 } \ 2321 return false; \ 2322} 2323 2324GEN_OPFV_TRANS(vfsqrt_v, opfv_check) 2325 2326/* Vector Floating-Point MIN/MAX Instructions */ 2327GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2328GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2329GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2330GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2331 2332/* Vector Floating-Point Sign-Injection Instructions */ 2333GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2334GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2335GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2336GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2337GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2338GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2339 2340/* Vector Floating-Point Compare Instructions */ 2341static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2342{ 2343 return require_rvv(s) && 2344 require_rvf(s) && 2345 vext_check_isa_ill(s) && 2346 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2347} 2348 2349GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2350GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2351GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2352GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2353GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) 2354 2355static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2356{ 2357 return require_rvv(s) && 2358 require_rvf(s) && 2359 vext_check_isa_ill(s) && 2360 vext_check_ms(s, a->rd, a->rs2); 2361} 2362 2363GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2364GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2365GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2366GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2367GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2368GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2369GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) 2370 2371/* Vector Floating-Point Classify Instruction */ 2372GEN_OPFV_TRANS(vfclass_v, opfv_check) 2373 2374/* Vector Floating-Point Merge Instruction */ 2375GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2376 2377static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2378{ 2379 if (require_rvv(s) && 2380 require_rvf(s) && 2381 vext_check_isa_ill(s) && 2382 require_align(a->rd, s->lmul)) { 2383 if (s->vl_eq_vlmax) { 2384 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2385 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); 2386 mark_vs_dirty(s); 2387 } else { 2388 TCGv_ptr dest; 2389 TCGv_i32 desc; 2390 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2391 static gen_helper_vmv_vx * const fns[3] = { 2392 gen_helper_vmv_v_x_h, 2393 gen_helper_vmv_v_x_w, 2394 gen_helper_vmv_v_x_d, 2395 }; 2396 TCGLabel *over = gen_new_label(); 2397 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2398 2399 dest = tcg_temp_new_ptr(); 2400 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2401 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2402 fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); 2403 2404 tcg_temp_free_ptr(dest); 2405 mark_vs_dirty(s); 2406 gen_set_label(over); 2407 } 2408 return true; 2409 } 2410 return false; 2411} 2412 2413/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2414GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) 2415GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) 2416GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) 2417GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) 2418 2419/* Widening Floating-Point/Integer Type-Convert Instructions */ 2420 2421/* 2422 * If the current SEW does not correspond to a supported IEEE floating-point 2423 * type, an illegal instruction exception is raised 2424 */ 2425static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2426{ 2427 return require_rvv(s) && 2428 require_scale_rvf(s) && 2429 (s->sew != MO_8) && 2430 vext_check_isa_ill(s) && 2431 vext_check_ds(s, a->rd, a->rs2, a->vm); 2432} 2433 2434#define GEN_OPFV_WIDEN_TRANS(NAME) \ 2435static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2436{ \ 2437 if (opfv_widen_check(s, a)) { \ 2438 uint32_t data = 0; \ 2439 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2440 gen_helper_##NAME##_h, \ 2441 gen_helper_##NAME##_w, \ 2442 }; \ 2443 TCGLabel *over = gen_new_label(); \ 2444 gen_set_rm(s, 7); \ 2445 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2446 \ 2447 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2448 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2449 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2450 vreg_ofs(s, a->rs2), cpu_env, \ 2451 s->vlen / 8, s->vlen / 8, data, \ 2452 fns[s->sew - 1]); \ 2453 mark_vs_dirty(s); \ 2454 gen_set_label(over); \ 2455 return true; \ 2456 } \ 2457 return false; \ 2458} 2459 2460GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) 2461GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) 2462GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) 2463GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) 2464GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) 2465 2466/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2467 2468/* 2469 * If the current SEW does not correspond to a supported IEEE floating-point 2470 * type, an illegal instruction exception is raised 2471 */ 2472static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2473{ 2474 return require_rvv(s) && 2475 require_rvf(s) && 2476 (s->sew != MO_64) && 2477 vext_check_isa_ill(s) && 2478 /* OPFV narrowing instructions ignore vs1 check */ 2479 vext_check_sd(s, a->rd, a->rs2, a->vm); 2480} 2481 2482#define GEN_OPFV_NARROW_TRANS(NAME) \ 2483static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2484{ \ 2485 if (opfv_narrow_check(s, a)) { \ 2486 uint32_t data = 0; \ 2487 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2488 gen_helper_##NAME##_h, \ 2489 gen_helper_##NAME##_w, \ 2490 }; \ 2491 TCGLabel *over = gen_new_label(); \ 2492 gen_set_rm(s, 7); \ 2493 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2494 \ 2495 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2496 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2497 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2498 vreg_ofs(s, a->rs2), cpu_env, \ 2499 s->vlen / 8, s->vlen / 8, data, \ 2500 fns[s->sew - 1]); \ 2501 mark_vs_dirty(s); \ 2502 gen_set_label(over); \ 2503 return true; \ 2504 } \ 2505 return false; \ 2506} 2507 2508GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) 2509GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) 2510GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) 2511GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) 2512GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) 2513 2514/* 2515 *** Vector Reduction Operations 2516 */ 2517/* Vector Single-Width Integer Reduction Instructions */ 2518static bool reduction_check(DisasContext *s, arg_rmrr *a) 2519{ 2520 return require_rvv(s) && 2521 vext_check_isa_ill(s) && 2522 vext_check_reduction(s, a->rs2); 2523} 2524 2525GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2526GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2527GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2528GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2529GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2530GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2531GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2532GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2533 2534/* Vector Widening Integer Reduction Instructions */ 2535static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2536{ 2537 return reduction_check(s, a) && (s->sew < MO_64); 2538} 2539 2540GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2541GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2542 2543/* Vector Single-Width Floating-Point Reduction Instructions */ 2544GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) 2545GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) 2546GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) 2547 2548/* Vector Widening Floating-Point Reduction Instructions */ 2549GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) 2550 2551/* 2552 *** Vector Mask Operations 2553 */ 2554 2555/* Vector Mask-Register Logical Instructions */ 2556#define GEN_MM_TRANS(NAME) \ 2557static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2558{ \ 2559 if (vext_check_isa_ill(s)) { \ 2560 uint32_t data = 0; \ 2561 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2562 TCGLabel *over = gen_new_label(); \ 2563 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2564 \ 2565 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2566 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2567 vreg_ofs(s, a->rs1), \ 2568 vreg_ofs(s, a->rs2), cpu_env, \ 2569 s->vlen / 8, s->vlen / 8, data, fn); \ 2570 mark_vs_dirty(s); \ 2571 gen_set_label(over); \ 2572 return true; \ 2573 } \ 2574 return false; \ 2575} 2576 2577GEN_MM_TRANS(vmand_mm) 2578GEN_MM_TRANS(vmnand_mm) 2579GEN_MM_TRANS(vmandnot_mm) 2580GEN_MM_TRANS(vmxor_mm) 2581GEN_MM_TRANS(vmor_mm) 2582GEN_MM_TRANS(vmnor_mm) 2583GEN_MM_TRANS(vmornot_mm) 2584GEN_MM_TRANS(vmxnor_mm) 2585 2586/* Vector mask population count vmpopc */ 2587static bool trans_vmpopc_m(DisasContext *s, arg_rmr *a) 2588{ 2589 if (require_rvv(s) && 2590 vext_check_isa_ill(s)) { 2591 TCGv_ptr src2, mask; 2592 TCGv dst; 2593 TCGv_i32 desc; 2594 uint32_t data = 0; 2595 data = FIELD_DP32(data, VDATA, VM, a->vm); 2596 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2597 2598 mask = tcg_temp_new_ptr(); 2599 src2 = tcg_temp_new_ptr(); 2600 dst = dest_gpr(s, a->rd); 2601 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2602 2603 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2604 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2605 2606 gen_helper_vmpopc_m(dst, mask, src2, cpu_env, desc); 2607 gen_set_gpr(s, a->rd, dst); 2608 2609 tcg_temp_free_ptr(mask); 2610 tcg_temp_free_ptr(src2); 2611 return true; 2612 } 2613 return false; 2614} 2615 2616/* vmfirst find-first-set mask bit */ 2617static bool trans_vmfirst_m(DisasContext *s, arg_rmr *a) 2618{ 2619 if (require_rvv(s) && 2620 vext_check_isa_ill(s)) { 2621 TCGv_ptr src2, mask; 2622 TCGv dst; 2623 TCGv_i32 desc; 2624 uint32_t data = 0; 2625 data = FIELD_DP32(data, VDATA, VM, a->vm); 2626 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2627 2628 mask = tcg_temp_new_ptr(); 2629 src2 = tcg_temp_new_ptr(); 2630 dst = dest_gpr(s, a->rd); 2631 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2632 2633 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2634 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2635 2636 gen_helper_vmfirst_m(dst, mask, src2, cpu_env, desc); 2637 gen_set_gpr(s, a->rd, dst); 2638 2639 tcg_temp_free_ptr(mask); 2640 tcg_temp_free_ptr(src2); 2641 return true; 2642 } 2643 return false; 2644} 2645 2646/* vmsbf.m set-before-first mask bit */ 2647/* vmsif.m set-includ-first mask bit */ 2648/* vmsof.m set-only-first mask bit */ 2649#define GEN_M_TRANS(NAME) \ 2650static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2651{ \ 2652 if (vext_check_isa_ill(s)) { \ 2653 uint32_t data = 0; \ 2654 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2655 TCGLabel *over = gen_new_label(); \ 2656 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2657 \ 2658 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2659 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2660 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2661 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2662 cpu_env, s->vlen / 8, s->vlen / 8, \ 2663 data, fn); \ 2664 mark_vs_dirty(s); \ 2665 gen_set_label(over); \ 2666 return true; \ 2667 } \ 2668 return false; \ 2669} 2670 2671GEN_M_TRANS(vmsbf_m) 2672GEN_M_TRANS(vmsif_m) 2673GEN_M_TRANS(vmsof_m) 2674 2675/* Vector Iota Instruction */ 2676static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2677{ 2678 if (require_rvv(s) && 2679 vext_check_isa_ill(s) && 2680 require_noover(a->rd, s->lmul, a->rs2, 0) && 2681 require_vm(a->vm, a->rd) && 2682 require_align(a->rd, s->lmul)) { 2683 uint32_t data = 0; 2684 TCGLabel *over = gen_new_label(); 2685 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2686 2687 data = FIELD_DP32(data, VDATA, VM, a->vm); 2688 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2689 static gen_helper_gvec_3_ptr * const fns[4] = { 2690 gen_helper_viota_m_b, gen_helper_viota_m_h, 2691 gen_helper_viota_m_w, gen_helper_viota_m_d, 2692 }; 2693 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2694 vreg_ofs(s, a->rs2), cpu_env, 2695 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 2696 mark_vs_dirty(s); 2697 gen_set_label(over); 2698 return true; 2699 } 2700 return false; 2701} 2702 2703/* Vector Element Index Instruction */ 2704static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 2705{ 2706 if (require_rvv(s) && 2707 vext_check_isa_ill(s) && 2708 require_align(a->rd, s->lmul) && 2709 require_vm(a->vm, a->rd)) { 2710 uint32_t data = 0; 2711 TCGLabel *over = gen_new_label(); 2712 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2713 2714 data = FIELD_DP32(data, VDATA, VM, a->vm); 2715 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2716 static gen_helper_gvec_2_ptr * const fns[4] = { 2717 gen_helper_vid_v_b, gen_helper_vid_v_h, 2718 gen_helper_vid_v_w, gen_helper_vid_v_d, 2719 }; 2720 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2721 cpu_env, s->vlen / 8, s->vlen / 8, 2722 data, fns[s->sew]); 2723 mark_vs_dirty(s); 2724 gen_set_label(over); 2725 return true; 2726 } 2727 return false; 2728} 2729 2730/* 2731 *** Vector Permutation Instructions 2732 */ 2733 2734/* Integer Extract Instruction */ 2735 2736static void load_element(TCGv_i64 dest, TCGv_ptr base, 2737 int ofs, int sew) 2738{ 2739 switch (sew) { 2740 case MO_8: 2741 tcg_gen_ld8u_i64(dest, base, ofs); 2742 break; 2743 case MO_16: 2744 tcg_gen_ld16u_i64(dest, base, ofs); 2745 break; 2746 case MO_32: 2747 tcg_gen_ld32u_i64(dest, base, ofs); 2748 break; 2749 case MO_64: 2750 tcg_gen_ld_i64(dest, base, ofs); 2751 break; 2752 default: 2753 g_assert_not_reached(); 2754 break; 2755 } 2756} 2757 2758/* offset of the idx element with base regsiter r */ 2759static uint32_t endian_ofs(DisasContext *s, int r, int idx) 2760{ 2761#ifdef HOST_WORDS_BIGENDIAN 2762 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 2763#else 2764 return vreg_ofs(s, r) + (idx << s->sew); 2765#endif 2766} 2767 2768/* adjust the index according to the endian */ 2769static void endian_adjust(TCGv_i32 ofs, int sew) 2770{ 2771#ifdef HOST_WORDS_BIGENDIAN 2772 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 2773#endif 2774} 2775 2776/* Load idx >= VLMAX ? 0 : vreg[idx] */ 2777static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 2778 int vreg, TCGv idx, int vlmax) 2779{ 2780 TCGv_i32 ofs = tcg_temp_new_i32(); 2781 TCGv_ptr base = tcg_temp_new_ptr(); 2782 TCGv_i64 t_idx = tcg_temp_new_i64(); 2783 TCGv_i64 t_vlmax, t_zero; 2784 2785 /* 2786 * Mask the index to the length so that we do 2787 * not produce an out-of-range load. 2788 */ 2789 tcg_gen_trunc_tl_i32(ofs, idx); 2790 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 2791 2792 /* Convert the index to an offset. */ 2793 endian_adjust(ofs, s->sew); 2794 tcg_gen_shli_i32(ofs, ofs, s->sew); 2795 2796 /* Convert the index to a pointer. */ 2797 tcg_gen_ext_i32_ptr(base, ofs); 2798 tcg_gen_add_ptr(base, base, cpu_env); 2799 2800 /* Perform the load. */ 2801 load_element(dest, base, 2802 vreg_ofs(s, vreg), s->sew); 2803 tcg_temp_free_ptr(base); 2804 tcg_temp_free_i32(ofs); 2805 2806 /* Flush out-of-range indexing to zero. */ 2807 t_vlmax = tcg_constant_i64(vlmax); 2808 t_zero = tcg_constant_i64(0); 2809 tcg_gen_extu_tl_i64(t_idx, idx); 2810 2811 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 2812 t_vlmax, dest, t_zero); 2813 2814 tcg_temp_free_i64(t_idx); 2815} 2816 2817static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 2818 int vreg, int idx) 2819{ 2820 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2821} 2822 2823static bool trans_vext_x_v(DisasContext *s, arg_r *a) 2824{ 2825 TCGv_i64 tmp = tcg_temp_new_i64(); 2826 TCGv dest = dest_gpr(s, a->rd); 2827 2828 if (a->rs1 == 0) { 2829 /* Special case vmv.x.s rd, vs2. */ 2830 vec_element_loadi(s, tmp, a->rs2, 0); 2831 } else { 2832 /* This instruction ignores LMUL and vector register groups */ 2833 int vlmax = s->vlen >> (3 + s->sew); 2834 vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); 2835 } 2836 2837 tcg_gen_trunc_i64_tl(dest, tmp); 2838 gen_set_gpr(s, a->rd, dest); 2839 2840 tcg_temp_free_i64(tmp); 2841 return true; 2842} 2843 2844/* Integer Scalar Move Instruction */ 2845 2846static void store_element(TCGv_i64 val, TCGv_ptr base, 2847 int ofs, int sew) 2848{ 2849 switch (sew) { 2850 case MO_8: 2851 tcg_gen_st8_i64(val, base, ofs); 2852 break; 2853 case MO_16: 2854 tcg_gen_st16_i64(val, base, ofs); 2855 break; 2856 case MO_32: 2857 tcg_gen_st32_i64(val, base, ofs); 2858 break; 2859 case MO_64: 2860 tcg_gen_st_i64(val, base, ofs); 2861 break; 2862 default: 2863 g_assert_not_reached(); 2864 break; 2865 } 2866} 2867 2868/* 2869 * Store vreg[idx] = val. 2870 * The index must be in range of VLMAX. 2871 */ 2872static void vec_element_storei(DisasContext *s, int vreg, 2873 int idx, TCGv_i64 val) 2874{ 2875 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2876} 2877 2878/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 2879static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 2880{ 2881 if (vext_check_isa_ill(s)) { 2882 /* This instruction ignores LMUL and vector register groups */ 2883 int maxsz = s->vlen >> 3; 2884 TCGv_i64 t1; 2885 TCGLabel *over = gen_new_label(); 2886 2887 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2888 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); 2889 if (a->rs1 == 0) { 2890 goto done; 2891 } 2892 2893 t1 = tcg_temp_new_i64(); 2894 tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); 2895 vec_element_storei(s, a->rd, 0, t1); 2896 tcg_temp_free_i64(t1); 2897 mark_vs_dirty(s); 2898 done: 2899 gen_set_label(over); 2900 return true; 2901 } 2902 return false; 2903} 2904 2905/* Floating-Point Scalar Move Instructions */ 2906static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 2907{ 2908 if (!s->vill && has_ext(s, RVF) && 2909 (s->mstatus_fs != 0) && (s->sew != 0)) { 2910 unsigned int len = 8 << s->sew; 2911 2912 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); 2913 if (len < 64) { 2914 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 2915 MAKE_64BIT_MASK(len, 64 - len)); 2916 } 2917 2918 mark_fs_dirty(s); 2919 return true; 2920 } 2921 return false; 2922} 2923 2924/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 2925static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 2926{ 2927 if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { 2928 TCGv_i64 t1; 2929 /* The instructions ignore LMUL and vector register group. */ 2930 uint32_t vlmax = s->vlen >> 3; 2931 2932 /* if vl == 0, skip vector register write back */ 2933 TCGLabel *over = gen_new_label(); 2934 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2935 2936 /* zeroed all elements */ 2937 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); 2938 2939 /* NaN-box f[rs1] as necessary for SEW */ 2940 t1 = tcg_temp_new_i64(); 2941 if (s->sew == MO_64 && !has_ext(s, RVD)) { 2942 tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); 2943 } else { 2944 tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); 2945 } 2946 vec_element_storei(s, a->rd, 0, t1); 2947 tcg_temp_free_i64(t1); 2948 mark_vs_dirty(s); 2949 gen_set_label(over); 2950 return true; 2951 } 2952 return false; 2953} 2954 2955/* Vector Slide Instructions */ 2956static bool slideup_check(DisasContext *s, arg_rmrr *a) 2957{ 2958 return require_rvv(s) && 2959 vext_check_isa_ill(s) && 2960 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 2961} 2962 2963GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 2964GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 2965GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 2966 2967static bool slidedown_check(DisasContext *s, arg_rmrr *a) 2968{ 2969 return require_rvv(s) && 2970 vext_check_isa_ill(s) && 2971 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 2972} 2973 2974GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 2975GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 2976GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 2977 2978/* Vector Register Gather Instruction */ 2979static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 2980{ 2981 return require_rvv(s) && 2982 vext_check_isa_ill(s) && 2983 require_align(a->rd, s->lmul) && 2984 require_align(a->rs1, s->lmul) && 2985 require_align(a->rs2, s->lmul) && 2986 (a->rd != a->rs2 && a->rd != a->rs1) && 2987 require_vm(a->vm, a->rd); 2988} 2989 2990GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 2991 2992static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 2993{ 2994 return require_rvv(s) && 2995 vext_check_isa_ill(s) && 2996 require_align(a->rd, s->lmul) && 2997 require_align(a->rs2, s->lmul) && 2998 (a->rd != a->rs2) && 2999 require_vm(a->vm, a->rd); 3000} 3001 3002/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3003static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3004{ 3005 if (!vrgather_vx_check(s, a)) { 3006 return false; 3007 } 3008 3009 if (a->vm && s->vl_eq_vlmax) { 3010 int vlmax = s->vlen; 3011 TCGv_i64 dest = tcg_temp_new_i64(); 3012 3013 if (a->rs1 == 0) { 3014 vec_element_loadi(s, dest, a->rs2, 0); 3015 } else { 3016 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3017 } 3018 3019 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3020 MAXSZ(s), MAXSZ(s), dest); 3021 tcg_temp_free_i64(dest); 3022 mark_vs_dirty(s); 3023 } else { 3024 static gen_helper_opivx * const fns[4] = { 3025 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3026 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3027 }; 3028 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3029 } 3030 return true; 3031} 3032 3033/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3034static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3035{ 3036 if (!vrgather_vx_check(s, a)) { 3037 return false; 3038 } 3039 3040 if (a->vm && s->vl_eq_vlmax) { 3041 if (a->rs1 >= s->vlen) { 3042 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), 3043 MAXSZ(s), MAXSZ(s), 0); 3044 } else { 3045 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3046 endian_ofs(s, a->rs2, a->rs1), 3047 MAXSZ(s), MAXSZ(s)); 3048 } 3049 mark_vs_dirty(s); 3050 } else { 3051 static gen_helper_opivx * const fns[4] = { 3052 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3053 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3054 }; 3055 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3056 s, IMM_ZX); 3057 } 3058 return true; 3059} 3060 3061/* 3062 * Vector Compress Instruction 3063 * 3064 * The destination vector register group cannot overlap the 3065 * source vector register group or the source mask register. 3066 */ 3067static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3068{ 3069 return require_rvv(s) && 3070 vext_check_isa_ill(s) && 3071 require_align(a->rd, s->lmul) && 3072 require_align(a->rs2, s->lmul) && 3073 (a->rd != a->rs2) && 3074 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1); 3075} 3076 3077static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3078{ 3079 if (vcompress_vm_check(s, a)) { 3080 uint32_t data = 0; 3081 static gen_helper_gvec_4_ptr * const fns[4] = { 3082 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3083 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3084 }; 3085 TCGLabel *over = gen_new_label(); 3086 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3087 3088 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3089 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3090 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3091 cpu_env, s->vlen / 8, s->vlen / 8, data, 3092 fns[s->sew]); 3093 mark_vs_dirty(s); 3094 gen_set_label(over); 3095 return true; 3096 } 3097 return false; 3098} 3099