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 543static uint8_t vext_get_emul(DisasContext *s, uint8_t eew) 544{ 545 int8_t emul = eew - s->sew + s->lmul; 546 return emul < 0 ? 0 : emul; 547} 548 549/* 550 *** unit stride load and store 551 */ 552typedef void gen_helper_ldst_us(TCGv_ptr, TCGv_ptr, TCGv, 553 TCGv_env, TCGv_i32); 554 555static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data, 556 gen_helper_ldst_us *fn, DisasContext *s, 557 bool is_store) 558{ 559 TCGv_ptr dest, mask; 560 TCGv base; 561 TCGv_i32 desc; 562 563 TCGLabel *over = gen_new_label(); 564 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 565 566 dest = tcg_temp_new_ptr(); 567 mask = tcg_temp_new_ptr(); 568 base = get_gpr(s, rs1, EXT_NONE); 569 570 /* 571 * As simd_desc supports at most 256 bytes, and in this implementation, 572 * the max vector group length is 2048 bytes. So split it into two parts. 573 * 574 * The first part is vlen in bytes, encoded in maxsz of simd_desc. 575 * The second part is lmul, encoded in data of simd_desc. 576 */ 577 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 578 579 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 580 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 581 582 fn(dest, mask, base, cpu_env, desc); 583 584 tcg_temp_free_ptr(dest); 585 tcg_temp_free_ptr(mask); 586 587 if (!is_store) { 588 mark_vs_dirty(s); 589 } 590 591 gen_set_label(over); 592 return true; 593} 594 595static bool ld_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 596{ 597 uint32_t data = 0; 598 gen_helper_ldst_us *fn; 599 static gen_helper_ldst_us * const fns[2][4] = { 600 /* masked unit stride load */ 601 { gen_helper_vle8_v_mask, gen_helper_vle16_v_mask, 602 gen_helper_vle32_v_mask, gen_helper_vle64_v_mask }, 603 /* unmasked unit stride load */ 604 { gen_helper_vle8_v, gen_helper_vle16_v, 605 gen_helper_vle32_v, gen_helper_vle64_v } 606 }; 607 608 fn = fns[a->vm][eew]; 609 if (fn == NULL) { 610 return false; 611 } 612 613 /* 614 * Vector load/store instructions have the EEW encoded 615 * directly in the instructions. The maximum vector size is 616 * calculated with EMUL rather than LMUL. 617 */ 618 uint8_t emul = vext_get_emul(s, eew); 619 data = FIELD_DP32(data, VDATA, VM, a->vm); 620 data = FIELD_DP32(data, VDATA, LMUL, emul); 621 data = FIELD_DP32(data, VDATA, NF, a->nf); 622 return ldst_us_trans(a->rd, a->rs1, data, fn, s, false); 623} 624 625static bool ld_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 626{ 627 return require_rvv(s) && 628 vext_check_isa_ill(s) && 629 vext_check_load(s, a->rd, a->nf, a->vm, eew); 630} 631 632GEN_VEXT_TRANS(vle8_v, MO_8, r2nfvm, ld_us_op, ld_us_check) 633GEN_VEXT_TRANS(vle16_v, MO_16, r2nfvm, ld_us_op, ld_us_check) 634GEN_VEXT_TRANS(vle32_v, MO_32, r2nfvm, ld_us_op, ld_us_check) 635GEN_VEXT_TRANS(vle64_v, MO_64, r2nfvm, ld_us_op, ld_us_check) 636 637static bool st_us_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 638{ 639 uint32_t data = 0; 640 gen_helper_ldst_us *fn; 641 static gen_helper_ldst_us * const fns[2][4] = { 642 /* masked unit stride store */ 643 { gen_helper_vse8_v_mask, gen_helper_vse16_v_mask, 644 gen_helper_vse32_v_mask, gen_helper_vse64_v_mask }, 645 /* unmasked unit stride store */ 646 { gen_helper_vse8_v, gen_helper_vse16_v, 647 gen_helper_vse32_v, gen_helper_vse64_v } 648 }; 649 650 fn = fns[a->vm][eew]; 651 if (fn == NULL) { 652 return false; 653 } 654 655 uint8_t emul = vext_get_emul(s, eew); 656 data = FIELD_DP32(data, VDATA, VM, a->vm); 657 data = FIELD_DP32(data, VDATA, LMUL, emul); 658 data = FIELD_DP32(data, VDATA, NF, a->nf); 659 return ldst_us_trans(a->rd, a->rs1, data, fn, s, true); 660} 661 662static bool st_us_check(DisasContext *s, arg_r2nfvm* a, uint8_t eew) 663{ 664 return require_rvv(s) && 665 vext_check_isa_ill(s) && 666 vext_check_store(s, a->rd, a->nf, eew); 667} 668 669GEN_VEXT_TRANS(vse8_v, MO_8, r2nfvm, st_us_op, st_us_check) 670GEN_VEXT_TRANS(vse16_v, MO_16, r2nfvm, st_us_op, st_us_check) 671GEN_VEXT_TRANS(vse32_v, MO_32, r2nfvm, st_us_op, st_us_check) 672GEN_VEXT_TRANS(vse64_v, MO_64, r2nfvm, st_us_op, st_us_check) 673 674/* 675 *** stride load and store 676 */ 677typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, 678 TCGv, TCGv_env, TCGv_i32); 679 680static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, 681 uint32_t data, gen_helper_ldst_stride *fn, 682 DisasContext *s, bool is_store) 683{ 684 TCGv_ptr dest, mask; 685 TCGv base, stride; 686 TCGv_i32 desc; 687 688 TCGLabel *over = gen_new_label(); 689 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 690 691 dest = tcg_temp_new_ptr(); 692 mask = tcg_temp_new_ptr(); 693 base = get_gpr(s, rs1, EXT_NONE); 694 stride = get_gpr(s, rs2, EXT_NONE); 695 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 696 697 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 698 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 699 700 fn(dest, mask, base, stride, cpu_env, desc); 701 702 tcg_temp_free_ptr(dest); 703 tcg_temp_free_ptr(mask); 704 705 if (!is_store) { 706 mark_vs_dirty(s); 707 } 708 709 gen_set_label(over); 710 return true; 711} 712 713static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 714{ 715 uint32_t data = 0; 716 gen_helper_ldst_stride *fn; 717 static gen_helper_ldst_stride * const fns[4] = { 718 gen_helper_vlse8_v, gen_helper_vlse16_v, 719 gen_helper_vlse32_v, gen_helper_vlse64_v 720 }; 721 722 fn = fns[eew]; 723 if (fn == NULL) { 724 return false; 725 } 726 727 uint8_t emul = vext_get_emul(s, eew); 728 data = FIELD_DP32(data, VDATA, VM, a->vm); 729 data = FIELD_DP32(data, VDATA, LMUL, emul); 730 data = FIELD_DP32(data, VDATA, NF, a->nf); 731 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 732} 733 734static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 735{ 736 return require_rvv(s) && 737 vext_check_isa_ill(s) && 738 vext_check_load(s, a->rd, a->nf, a->vm, eew); 739} 740 741GEN_VEXT_TRANS(vlse8_v, MO_8, rnfvm, ld_stride_op, ld_stride_check) 742GEN_VEXT_TRANS(vlse16_v, MO_16, rnfvm, ld_stride_op, ld_stride_check) 743GEN_VEXT_TRANS(vlse32_v, MO_32, rnfvm, ld_stride_op, ld_stride_check) 744GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) 745 746static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 747{ 748 uint32_t data = 0; 749 gen_helper_ldst_stride *fn; 750 static gen_helper_ldst_stride * const fns[4] = { 751 /* masked stride store */ 752 gen_helper_vsse8_v, gen_helper_vsse16_v, 753 gen_helper_vsse32_v, gen_helper_vsse64_v 754 }; 755 756 uint8_t emul = vext_get_emul(s, eew); 757 data = FIELD_DP32(data, VDATA, VM, a->vm); 758 data = FIELD_DP32(data, VDATA, LMUL, emul); 759 data = FIELD_DP32(data, VDATA, NF, a->nf); 760 fn = fns[eew]; 761 if (fn == NULL) { 762 return false; 763 } 764 765 return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); 766} 767 768static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 769{ 770 return require_rvv(s) && 771 vext_check_isa_ill(s) && 772 vext_check_store(s, a->rd, a->nf, eew); 773} 774 775GEN_VEXT_TRANS(vsse8_v, MO_8, rnfvm, st_stride_op, st_stride_check) 776GEN_VEXT_TRANS(vsse16_v, MO_16, rnfvm, st_stride_op, st_stride_check) 777GEN_VEXT_TRANS(vsse32_v, MO_32, rnfvm, st_stride_op, st_stride_check) 778GEN_VEXT_TRANS(vsse64_v, MO_64, rnfvm, st_stride_op, st_stride_check) 779 780/* 781 *** index load and store 782 */ 783typedef void gen_helper_ldst_index(TCGv_ptr, TCGv_ptr, TCGv, 784 TCGv_ptr, TCGv_env, TCGv_i32); 785 786static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 787 uint32_t data, gen_helper_ldst_index *fn, 788 DisasContext *s, bool is_store) 789{ 790 TCGv_ptr dest, mask, index; 791 TCGv base; 792 TCGv_i32 desc; 793 794 TCGLabel *over = gen_new_label(); 795 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 796 797 dest = tcg_temp_new_ptr(); 798 mask = tcg_temp_new_ptr(); 799 index = tcg_temp_new_ptr(); 800 base = get_gpr(s, rs1, EXT_NONE); 801 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 802 803 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 804 tcg_gen_addi_ptr(index, cpu_env, vreg_ofs(s, vs2)); 805 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 806 807 fn(dest, mask, base, index, cpu_env, desc); 808 809 tcg_temp_free_ptr(dest); 810 tcg_temp_free_ptr(mask); 811 tcg_temp_free_ptr(index); 812 813 if (!is_store) { 814 mark_vs_dirty(s); 815 } 816 817 gen_set_label(over); 818 return true; 819} 820 821static bool ld_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 822{ 823 uint32_t data = 0; 824 gen_helper_ldst_index *fn; 825 static gen_helper_ldst_index * const fns[4][4] = { 826 /* 827 * offset vector register group EEW = 8, 828 * data vector register group EEW = SEW 829 */ 830 { gen_helper_vlxei8_8_v, gen_helper_vlxei8_16_v, 831 gen_helper_vlxei8_32_v, gen_helper_vlxei8_64_v }, 832 /* 833 * offset vector register group EEW = 16, 834 * data vector register group EEW = SEW 835 */ 836 { gen_helper_vlxei16_8_v, gen_helper_vlxei16_16_v, 837 gen_helper_vlxei16_32_v, gen_helper_vlxei16_64_v }, 838 /* 839 * offset vector register group EEW = 32, 840 * data vector register group EEW = SEW 841 */ 842 { gen_helper_vlxei32_8_v, gen_helper_vlxei32_16_v, 843 gen_helper_vlxei32_32_v, gen_helper_vlxei32_64_v }, 844 /* 845 * offset vector register group EEW = 64, 846 * data vector register group EEW = SEW 847 */ 848 { gen_helper_vlxei64_8_v, gen_helper_vlxei64_16_v, 849 gen_helper_vlxei64_32_v, gen_helper_vlxei64_64_v } 850 }; 851 852 fn = fns[eew][s->sew]; 853 854 uint8_t emul = vext_get_emul(s, s->sew); 855 data = FIELD_DP32(data, VDATA, VM, a->vm); 856 data = FIELD_DP32(data, VDATA, LMUL, emul); 857 data = FIELD_DP32(data, VDATA, NF, a->nf); 858 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, false); 859} 860 861static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 862{ 863 return require_rvv(s) && 864 vext_check_isa_ill(s) && 865 vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); 866} 867 868GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) 869GEN_VEXT_TRANS(vlxei16_v, MO_16, rnfvm, ld_index_op, ld_index_check) 870GEN_VEXT_TRANS(vlxei32_v, MO_32, rnfvm, ld_index_op, ld_index_check) 871GEN_VEXT_TRANS(vlxei64_v, MO_64, rnfvm, ld_index_op, ld_index_check) 872 873static bool st_index_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) 874{ 875 uint32_t data = 0; 876 gen_helper_ldst_index *fn; 877 static gen_helper_ldst_index * const fns[4][4] = { 878 /* 879 * offset vector register group EEW = 8, 880 * data vector register group EEW = SEW 881 */ 882 { gen_helper_vsxei8_8_v, gen_helper_vsxei8_16_v, 883 gen_helper_vsxei8_32_v, gen_helper_vsxei8_64_v }, 884 /* 885 * offset vector register group EEW = 16, 886 * data vector register group EEW = SEW 887 */ 888 { gen_helper_vsxei16_8_v, gen_helper_vsxei16_16_v, 889 gen_helper_vsxei16_32_v, gen_helper_vsxei16_64_v }, 890 /* 891 * offset vector register group EEW = 32, 892 * data vector register group EEW = SEW 893 */ 894 { gen_helper_vsxei32_8_v, gen_helper_vsxei32_16_v, 895 gen_helper_vsxei32_32_v, gen_helper_vsxei32_64_v }, 896 /* 897 * offset vector register group EEW = 64, 898 * data vector register group EEW = SEW 899 */ 900 { gen_helper_vsxei64_8_v, gen_helper_vsxei64_16_v, 901 gen_helper_vsxei64_32_v, gen_helper_vsxei64_64_v } 902 }; 903 904 fn = fns[eew][s->sew]; 905 906 uint8_t emul = vext_get_emul(s, s->sew); 907 data = FIELD_DP32(data, VDATA, VM, a->vm); 908 data = FIELD_DP32(data, VDATA, LMUL, emul); 909 data = FIELD_DP32(data, VDATA, NF, a->nf); 910 return ldst_index_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); 911} 912 913static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) 914{ 915 return require_rvv(s) && 916 vext_check_isa_ill(s) && 917 vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); 918} 919 920GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) 921GEN_VEXT_TRANS(vsxei16_v, MO_16, rnfvm, st_index_op, st_index_check) 922GEN_VEXT_TRANS(vsxei32_v, MO_32, rnfvm, st_index_op, st_index_check) 923GEN_VEXT_TRANS(vsxei64_v, MO_64, rnfvm, st_index_op, st_index_check) 924 925/* 926 *** unit stride fault-only-first load 927 */ 928static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data, 929 gen_helper_ldst_us *fn, DisasContext *s) 930{ 931 TCGv_ptr dest, mask; 932 TCGv base; 933 TCGv_i32 desc; 934 935 TCGLabel *over = gen_new_label(); 936 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 937 938 dest = tcg_temp_new_ptr(); 939 mask = tcg_temp_new_ptr(); 940 base = get_gpr(s, rs1, EXT_NONE); 941 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 942 943 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 944 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 945 946 fn(dest, mask, base, cpu_env, desc); 947 948 tcg_temp_free_ptr(dest); 949 tcg_temp_free_ptr(mask); 950 mark_vs_dirty(s); 951 gen_set_label(over); 952 return true; 953} 954 955static bool ldff_op(DisasContext *s, arg_r2nfvm *a, uint8_t eew) 956{ 957 uint32_t data = 0; 958 gen_helper_ldst_us *fn; 959 static gen_helper_ldst_us * const fns[4] = { 960 gen_helper_vle8ff_v, gen_helper_vle16ff_v, 961 gen_helper_vle32ff_v, gen_helper_vle64ff_v 962 }; 963 964 fn = fns[eew]; 965 if (fn == NULL) { 966 return false; 967 } 968 969 uint8_t emul = vext_get_emul(s, eew); 970 data = FIELD_DP32(data, VDATA, VM, a->vm); 971 data = FIELD_DP32(data, VDATA, LMUL, emul); 972 data = FIELD_DP32(data, VDATA, NF, a->nf); 973 return ldff_trans(a->rd, a->rs1, data, fn, s); 974} 975 976GEN_VEXT_TRANS(vle8ff_v, MO_8, r2nfvm, ldff_op, ld_us_check) 977GEN_VEXT_TRANS(vle16ff_v, MO_16, r2nfvm, ldff_op, ld_us_check) 978GEN_VEXT_TRANS(vle32ff_v, MO_32, r2nfvm, ldff_op, ld_us_check) 979GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) 980 981/* 982 * load and store whole register instructions 983 */ 984typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); 985 986static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, 987 gen_helper_ldst_whole *fn, DisasContext *s, 988 bool is_store) 989{ 990 TCGv_ptr dest; 991 TCGv base; 992 TCGv_i32 desc; 993 994 uint32_t data = FIELD_DP32(0, VDATA, NF, nf); 995 dest = tcg_temp_new_ptr(); 996 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 997 998 base = get_gpr(s, rs1, EXT_NONE); 999 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1000 1001 fn(dest, base, cpu_env, desc); 1002 1003 tcg_temp_free_ptr(dest); 1004 1005 if (!is_store) { 1006 mark_vs_dirty(s); 1007 } 1008 1009 return true; 1010} 1011 1012/* 1013 * load and store whole register instructions ignore vtype and vl setting. 1014 * Thus, we don't need to check vill bit. (Section 7.9) 1015 */ 1016#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF, IS_STORE) \ 1017static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ 1018{ \ 1019 if (require_rvv(s) && \ 1020 QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ 1021 return ldst_whole_trans(a->rd, a->rs1, ARG_NF, gen_helper_##NAME, \ 1022 s, IS_STORE); \ 1023 } \ 1024 return false; \ 1025} 1026 1027GEN_LDST_WHOLE_TRANS(vl1re8_v, 1, false) 1028GEN_LDST_WHOLE_TRANS(vl1re16_v, 1, false) 1029GEN_LDST_WHOLE_TRANS(vl1re32_v, 1, false) 1030GEN_LDST_WHOLE_TRANS(vl1re64_v, 1, false) 1031GEN_LDST_WHOLE_TRANS(vl2re8_v, 2, false) 1032GEN_LDST_WHOLE_TRANS(vl2re16_v, 2, false) 1033GEN_LDST_WHOLE_TRANS(vl2re32_v, 2, false) 1034GEN_LDST_WHOLE_TRANS(vl2re64_v, 2, false) 1035GEN_LDST_WHOLE_TRANS(vl4re8_v, 4, false) 1036GEN_LDST_WHOLE_TRANS(vl4re16_v, 4, false) 1037GEN_LDST_WHOLE_TRANS(vl4re32_v, 4, false) 1038GEN_LDST_WHOLE_TRANS(vl4re64_v, 4, false) 1039GEN_LDST_WHOLE_TRANS(vl8re8_v, 8, false) 1040GEN_LDST_WHOLE_TRANS(vl8re16_v, 8, false) 1041GEN_LDST_WHOLE_TRANS(vl8re32_v, 8, false) 1042GEN_LDST_WHOLE_TRANS(vl8re64_v, 8, false) 1043 1044GEN_LDST_WHOLE_TRANS(vs1r_v, 1, true) 1045GEN_LDST_WHOLE_TRANS(vs2r_v, 2, true) 1046GEN_LDST_WHOLE_TRANS(vs4r_v, 4, true) 1047GEN_LDST_WHOLE_TRANS(vs8r_v, 8, true) 1048 1049/* 1050 *** Vector Integer Arithmetic Instructions 1051 */ 1052 1053/* 1054 * MAXSZ returns the maximum vector size can be operated in bytes, 1055 * which is used in GVEC IR when vl_eq_vlmax flag is set to true 1056 * to accerlate vector operation. 1057 */ 1058static inline uint32_t MAXSZ(DisasContext *s) 1059{ 1060 int scale = s->lmul - 3; 1061 return scale < 0 ? s->vlen >> -scale : s->vlen << scale; 1062} 1063 1064static bool opivv_check(DisasContext *s, arg_rmrr *a) 1065{ 1066 return require_rvv(s) && 1067 vext_check_isa_ill(s) && 1068 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1069} 1070 1071typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, 1072 uint32_t, uint32_t, uint32_t); 1073 1074static inline bool 1075do_opivv_gvec(DisasContext *s, arg_rmrr *a, GVecGen3Fn *gvec_fn, 1076 gen_helper_gvec_4_ptr *fn) 1077{ 1078 TCGLabel *over = gen_new_label(); 1079 if (!opivv_check(s, a)) { 1080 return false; 1081 } 1082 1083 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1084 1085 if (a->vm && s->vl_eq_vlmax) { 1086 gvec_fn(s->sew, vreg_ofs(s, a->rd), 1087 vreg_ofs(s, a->rs2), vreg_ofs(s, a->rs1), 1088 MAXSZ(s), MAXSZ(s)); 1089 } else { 1090 uint32_t data = 0; 1091 1092 data = FIELD_DP32(data, VDATA, VM, a->vm); 1093 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1094 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1095 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 1096 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1097 } 1098 mark_vs_dirty(s); 1099 gen_set_label(over); 1100 return true; 1101} 1102 1103/* OPIVV with GVEC IR */ 1104#define GEN_OPIVV_GVEC_TRANS(NAME, SUF) \ 1105static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1106{ \ 1107 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1108 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1109 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1110 }; \ 1111 return do_opivv_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1112} 1113 1114GEN_OPIVV_GVEC_TRANS(vadd_vv, add) 1115GEN_OPIVV_GVEC_TRANS(vsub_vv, sub) 1116 1117typedef void gen_helper_opivx(TCGv_ptr, TCGv_ptr, TCGv, TCGv_ptr, 1118 TCGv_env, TCGv_i32); 1119 1120static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, 1121 gen_helper_opivx *fn, DisasContext *s) 1122{ 1123 TCGv_ptr dest, src2, mask; 1124 TCGv src1; 1125 TCGv_i32 desc; 1126 uint32_t data = 0; 1127 1128 TCGLabel *over = gen_new_label(); 1129 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1130 1131 dest = tcg_temp_new_ptr(); 1132 mask = tcg_temp_new_ptr(); 1133 src2 = tcg_temp_new_ptr(); 1134 src1 = get_gpr(s, rs1, EXT_NONE); 1135 1136 data = FIELD_DP32(data, VDATA, VM, vm); 1137 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1138 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1139 1140 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1141 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1142 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1143 1144 fn(dest, mask, src1, src2, cpu_env, desc); 1145 1146 tcg_temp_free_ptr(dest); 1147 tcg_temp_free_ptr(mask); 1148 tcg_temp_free_ptr(src2); 1149 mark_vs_dirty(s); 1150 gen_set_label(over); 1151 return true; 1152} 1153 1154static bool opivx_check(DisasContext *s, arg_rmrr *a) 1155{ 1156 return require_rvv(s) && 1157 vext_check_isa_ill(s) && 1158 vext_check_ss(s, a->rd, a->rs2, a->vm); 1159} 1160 1161typedef void GVecGen2sFn(unsigned, uint32_t, uint32_t, TCGv_i64, 1162 uint32_t, uint32_t); 1163 1164static inline bool 1165do_opivx_gvec(DisasContext *s, arg_rmrr *a, GVecGen2sFn *gvec_fn, 1166 gen_helper_opivx *fn) 1167{ 1168 if (!opivx_check(s, a)) { 1169 return false; 1170 } 1171 1172 if (a->vm && s->vl_eq_vlmax) { 1173 TCGv_i64 src1 = tcg_temp_new_i64(); 1174 1175 tcg_gen_ext_tl_i64(src1, get_gpr(s, a->rs1, EXT_SIGN)); 1176 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1177 src1, MAXSZ(s), MAXSZ(s)); 1178 1179 tcg_temp_free_i64(src1); 1180 mark_vs_dirty(s); 1181 return true; 1182 } 1183 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1184} 1185 1186/* OPIVX with GVEC IR */ 1187#define GEN_OPIVX_GVEC_TRANS(NAME, SUF) \ 1188static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1189{ \ 1190 static gen_helper_opivx * const fns[4] = { \ 1191 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1192 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1193 }; \ 1194 return do_opivx_gvec(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1195} 1196 1197GEN_OPIVX_GVEC_TRANS(vadd_vx, adds) 1198GEN_OPIVX_GVEC_TRANS(vsub_vx, subs) 1199 1200static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1201{ 1202 tcg_gen_vec_sub8_i64(d, b, a); 1203} 1204 1205static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) 1206{ 1207 tcg_gen_vec_sub16_i64(d, b, a); 1208} 1209 1210static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) 1211{ 1212 tcg_gen_sub_i32(ret, arg2, arg1); 1213} 1214 1215static void gen_rsub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) 1216{ 1217 tcg_gen_sub_i64(ret, arg2, arg1); 1218} 1219 1220static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b) 1221{ 1222 tcg_gen_sub_vec(vece, r, b, a); 1223} 1224 1225static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs, 1226 TCGv_i64 c, uint32_t oprsz, uint32_t maxsz) 1227{ 1228 static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 }; 1229 static const GVecGen2s rsub_op[4] = { 1230 { .fni8 = gen_vec_rsub8_i64, 1231 .fniv = gen_rsub_vec, 1232 .fno = gen_helper_vec_rsubs8, 1233 .opt_opc = vecop_list, 1234 .vece = MO_8 }, 1235 { .fni8 = gen_vec_rsub16_i64, 1236 .fniv = gen_rsub_vec, 1237 .fno = gen_helper_vec_rsubs16, 1238 .opt_opc = vecop_list, 1239 .vece = MO_16 }, 1240 { .fni4 = gen_rsub_i32, 1241 .fniv = gen_rsub_vec, 1242 .fno = gen_helper_vec_rsubs32, 1243 .opt_opc = vecop_list, 1244 .vece = MO_32 }, 1245 { .fni8 = gen_rsub_i64, 1246 .fniv = gen_rsub_vec, 1247 .fno = gen_helper_vec_rsubs64, 1248 .opt_opc = vecop_list, 1249 .prefer_i64 = TCG_TARGET_REG_BITS == 64, 1250 .vece = MO_64 }, 1251 }; 1252 1253 tcg_debug_assert(vece <= MO_64); 1254 tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &rsub_op[vece]); 1255} 1256 1257GEN_OPIVX_GVEC_TRANS(vrsub_vx, rsubs) 1258 1259typedef enum { 1260 IMM_ZX, /* Zero-extended */ 1261 IMM_SX, /* Sign-extended */ 1262 IMM_TRUNC_SEW, /* Truncate to log(SEW) bits */ 1263 IMM_TRUNC_2SEW, /* Truncate to log(2*SEW) bits */ 1264} imm_mode_t; 1265 1266static int64_t extract_imm(DisasContext *s, uint32_t imm, imm_mode_t imm_mode) 1267{ 1268 switch (imm_mode) { 1269 case IMM_ZX: 1270 return extract64(imm, 0, 5); 1271 case IMM_SX: 1272 return sextract64(imm, 0, 5); 1273 case IMM_TRUNC_SEW: 1274 return extract64(imm, 0, s->sew + 3); 1275 case IMM_TRUNC_2SEW: 1276 return extract64(imm, 0, s->sew + 4); 1277 default: 1278 g_assert_not_reached(); 1279 } 1280} 1281 1282static bool opivi_trans(uint32_t vd, uint32_t imm, uint32_t vs2, uint32_t vm, 1283 gen_helper_opivx *fn, DisasContext *s, 1284 imm_mode_t imm_mode) 1285{ 1286 TCGv_ptr dest, src2, mask; 1287 TCGv src1; 1288 TCGv_i32 desc; 1289 uint32_t data = 0; 1290 1291 TCGLabel *over = gen_new_label(); 1292 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1293 1294 dest = tcg_temp_new_ptr(); 1295 mask = tcg_temp_new_ptr(); 1296 src2 = tcg_temp_new_ptr(); 1297 src1 = tcg_constant_tl(extract_imm(s, imm, imm_mode)); 1298 1299 data = FIELD_DP32(data, VDATA, VM, vm); 1300 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1301 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1302 1303 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 1304 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 1305 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 1306 1307 fn(dest, mask, src1, src2, cpu_env, desc); 1308 1309 tcg_temp_free_ptr(dest); 1310 tcg_temp_free_ptr(mask); 1311 tcg_temp_free_ptr(src2); 1312 mark_vs_dirty(s); 1313 gen_set_label(over); 1314 return true; 1315} 1316 1317typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, 1318 uint32_t, uint32_t); 1319 1320static inline bool 1321do_opivi_gvec(DisasContext *s, arg_rmrr *a, GVecGen2iFn *gvec_fn, 1322 gen_helper_opivx *fn, imm_mode_t imm_mode) 1323{ 1324 if (!opivx_check(s, a)) { 1325 return false; 1326 } 1327 1328 if (a->vm && s->vl_eq_vlmax) { 1329 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1330 extract_imm(s, a->rs1, imm_mode), MAXSZ(s), MAXSZ(s)); 1331 mark_vs_dirty(s); 1332 return true; 1333 } 1334 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s, imm_mode); 1335} 1336 1337/* OPIVI with GVEC IR */ 1338#define GEN_OPIVI_GVEC_TRANS(NAME, IMM_MODE, OPIVX, SUF) \ 1339static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1340{ \ 1341 static gen_helper_opivx * const fns[4] = { \ 1342 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1343 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1344 }; \ 1345 return do_opivi_gvec(s, a, tcg_gen_gvec_##SUF, \ 1346 fns[s->sew], IMM_MODE); \ 1347} 1348 1349GEN_OPIVI_GVEC_TRANS(vadd_vi, IMM_SX, vadd_vx, addi) 1350 1351static void tcg_gen_gvec_rsubi(unsigned vece, uint32_t dofs, uint32_t aofs, 1352 int64_t c, uint32_t oprsz, uint32_t maxsz) 1353{ 1354 TCGv_i64 tmp = tcg_constant_i64(c); 1355 tcg_gen_gvec_rsubs(vece, dofs, aofs, tmp, oprsz, maxsz); 1356} 1357 1358GEN_OPIVI_GVEC_TRANS(vrsub_vi, IMM_SX, vrsub_vx, rsubi) 1359 1360/* Vector Widening Integer Add/Subtract */ 1361 1362/* OPIVV with WIDEN */ 1363static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) 1364{ 1365 return require_rvv(s) && 1366 vext_check_isa_ill(s) && 1367 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 1368} 1369 1370static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, 1371 gen_helper_gvec_4_ptr *fn, 1372 bool (*checkfn)(DisasContext *, arg_rmrr *)) 1373{ 1374 if (checkfn(s, a)) { 1375 uint32_t data = 0; 1376 TCGLabel *over = gen_new_label(); 1377 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1378 1379 data = FIELD_DP32(data, VDATA, VM, a->vm); 1380 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1381 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1382 vreg_ofs(s, a->rs1), 1383 vreg_ofs(s, a->rs2), 1384 cpu_env, s->vlen / 8, s->vlen / 8, 1385 data, fn); 1386 mark_vs_dirty(s); 1387 gen_set_label(over); 1388 return true; 1389 } 1390 return false; 1391} 1392 1393#define GEN_OPIVV_WIDEN_TRANS(NAME, CHECK) \ 1394static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1395{ \ 1396 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1397 gen_helper_##NAME##_b, \ 1398 gen_helper_##NAME##_h, \ 1399 gen_helper_##NAME##_w \ 1400 }; \ 1401 return do_opivv_widen(s, a, fns[s->sew], CHECK); \ 1402} 1403 1404GEN_OPIVV_WIDEN_TRANS(vwaddu_vv, opivv_widen_check) 1405GEN_OPIVV_WIDEN_TRANS(vwadd_vv, opivv_widen_check) 1406GEN_OPIVV_WIDEN_TRANS(vwsubu_vv, opivv_widen_check) 1407GEN_OPIVV_WIDEN_TRANS(vwsub_vv, opivv_widen_check) 1408 1409/* OPIVX with WIDEN */ 1410static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) 1411{ 1412 return require_rvv(s) && 1413 vext_check_isa_ill(s) && 1414 vext_check_ds(s, a->rd, a->rs2, a->vm); 1415} 1416 1417static bool do_opivx_widen(DisasContext *s, arg_rmrr *a, 1418 gen_helper_opivx *fn) 1419{ 1420 if (opivx_widen_check(s, a)) { 1421 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1422 } 1423 return false; 1424} 1425 1426#define GEN_OPIVX_WIDEN_TRANS(NAME) \ 1427static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1428{ \ 1429 static gen_helper_opivx * const fns[3] = { \ 1430 gen_helper_##NAME##_b, \ 1431 gen_helper_##NAME##_h, \ 1432 gen_helper_##NAME##_w \ 1433 }; \ 1434 return do_opivx_widen(s, a, fns[s->sew]); \ 1435} 1436 1437GEN_OPIVX_WIDEN_TRANS(vwaddu_vx) 1438GEN_OPIVX_WIDEN_TRANS(vwadd_vx) 1439GEN_OPIVX_WIDEN_TRANS(vwsubu_vx) 1440GEN_OPIVX_WIDEN_TRANS(vwsub_vx) 1441 1442/* WIDEN OPIVV with WIDEN */ 1443static bool opiwv_widen_check(DisasContext *s, arg_rmrr *a) 1444{ 1445 return require_rvv(s) && 1446 vext_check_isa_ill(s) && 1447 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 1448} 1449 1450static bool do_opiwv_widen(DisasContext *s, arg_rmrr *a, 1451 gen_helper_gvec_4_ptr *fn) 1452{ 1453 if (opiwv_widen_check(s, a)) { 1454 uint32_t data = 0; 1455 TCGLabel *over = gen_new_label(); 1456 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1457 1458 data = FIELD_DP32(data, VDATA, VM, a->vm); 1459 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 1460 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 1461 vreg_ofs(s, a->rs1), 1462 vreg_ofs(s, a->rs2), 1463 cpu_env, s->vlen / 8, s->vlen / 8, data, fn); 1464 mark_vs_dirty(s); 1465 gen_set_label(over); 1466 return true; 1467 } 1468 return false; 1469} 1470 1471#define GEN_OPIWV_WIDEN_TRANS(NAME) \ 1472static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1473{ \ 1474 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1475 gen_helper_##NAME##_b, \ 1476 gen_helper_##NAME##_h, \ 1477 gen_helper_##NAME##_w \ 1478 }; \ 1479 return do_opiwv_widen(s, a, fns[s->sew]); \ 1480} 1481 1482GEN_OPIWV_WIDEN_TRANS(vwaddu_wv) 1483GEN_OPIWV_WIDEN_TRANS(vwadd_wv) 1484GEN_OPIWV_WIDEN_TRANS(vwsubu_wv) 1485GEN_OPIWV_WIDEN_TRANS(vwsub_wv) 1486 1487/* WIDEN OPIVX with WIDEN */ 1488static bool opiwx_widen_check(DisasContext *s, arg_rmrr *a) 1489{ 1490 return require_rvv(s) && 1491 vext_check_isa_ill(s) && 1492 vext_check_dd(s, a->rd, a->rs2, a->vm); 1493} 1494 1495static bool do_opiwx_widen(DisasContext *s, arg_rmrr *a, 1496 gen_helper_opivx *fn) 1497{ 1498 if (opiwx_widen_check(s, a)) { 1499 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1500 } 1501 return false; 1502} 1503 1504#define GEN_OPIWX_WIDEN_TRANS(NAME) \ 1505static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1506{ \ 1507 static gen_helper_opivx * const fns[3] = { \ 1508 gen_helper_##NAME##_b, \ 1509 gen_helper_##NAME##_h, \ 1510 gen_helper_##NAME##_w \ 1511 }; \ 1512 return do_opiwx_widen(s, a, fns[s->sew]); \ 1513} 1514 1515GEN_OPIWX_WIDEN_TRANS(vwaddu_wx) 1516GEN_OPIWX_WIDEN_TRANS(vwadd_wx) 1517GEN_OPIWX_WIDEN_TRANS(vwsubu_wx) 1518GEN_OPIWX_WIDEN_TRANS(vwsub_wx) 1519 1520/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */ 1521/* OPIVV without GVEC IR */ 1522#define GEN_OPIVV_TRANS(NAME, CHECK) \ 1523static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1524{ \ 1525 if (CHECK(s, a)) { \ 1526 uint32_t data = 0; \ 1527 static gen_helper_gvec_4_ptr * const fns[4] = { \ 1528 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1529 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1530 }; \ 1531 TCGLabel *over = gen_new_label(); \ 1532 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1533 \ 1534 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1535 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1536 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1537 vreg_ofs(s, a->rs1), \ 1538 vreg_ofs(s, a->rs2), cpu_env, \ 1539 s->vlen / 8, s->vlen / 8, data, \ 1540 fns[s->sew]); \ 1541 mark_vs_dirty(s); \ 1542 gen_set_label(over); \ 1543 return true; \ 1544 } \ 1545 return false; \ 1546} 1547 1548/* 1549 * For vadc and vsbc, an illegal instruction exception is raised if the 1550 * destination vector register is v0 and LMUL > 1. (Section 12.3) 1551 */ 1552static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a) 1553{ 1554 return require_rvv(s) && 1555 vext_check_isa_ill(s) && 1556 (a->rd != 0) && 1557 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 1558} 1559 1560GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check) 1561GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check) 1562 1563/* 1564 * For vmadc and vmsbc, an illegal instruction exception is raised if the 1565 * destination vector register overlaps a source vector register group. 1566 */ 1567static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a) 1568{ 1569 return require_rvv(s) && 1570 vext_check_isa_ill(s) && 1571 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1572} 1573 1574GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check) 1575GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check) 1576 1577static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a) 1578{ 1579 return require_rvv(s) && 1580 vext_check_isa_ill(s) && 1581 (a->rd != 0) && 1582 vext_check_ss(s, a->rd, a->rs2, a->vm); 1583} 1584 1585/* OPIVX without GVEC IR */ 1586#define GEN_OPIVX_TRANS(NAME, CHECK) \ 1587static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1588{ \ 1589 if (CHECK(s, a)) { \ 1590 static gen_helper_opivx * const fns[4] = { \ 1591 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1592 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1593 }; \ 1594 \ 1595 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1596 } \ 1597 return false; \ 1598} 1599 1600GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check) 1601GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check) 1602 1603static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a) 1604{ 1605 return require_rvv(s) && 1606 vext_check_isa_ill(s) && 1607 vext_check_ms(s, a->rd, a->rs2); 1608} 1609 1610GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check) 1611GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check) 1612 1613/* OPIVI without GVEC IR */ 1614#define GEN_OPIVI_TRANS(NAME, IMM_MODE, OPIVX, CHECK) \ 1615static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1616{ \ 1617 if (CHECK(s, a)) { \ 1618 static gen_helper_opivx * const fns[4] = { \ 1619 gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \ 1620 gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \ 1621 }; \ 1622 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1623 fns[s->sew], s, IMM_MODE); \ 1624 } \ 1625 return false; \ 1626} 1627 1628GEN_OPIVI_TRANS(vadc_vim, IMM_SX, vadc_vxm, opivx_vadc_check) 1629GEN_OPIVI_TRANS(vmadc_vim, IMM_SX, vmadc_vxm, opivx_vmadc_check) 1630 1631/* Vector Bitwise Logical Instructions */ 1632GEN_OPIVV_GVEC_TRANS(vand_vv, and) 1633GEN_OPIVV_GVEC_TRANS(vor_vv, or) 1634GEN_OPIVV_GVEC_TRANS(vxor_vv, xor) 1635GEN_OPIVX_GVEC_TRANS(vand_vx, ands) 1636GEN_OPIVX_GVEC_TRANS(vor_vx, ors) 1637GEN_OPIVX_GVEC_TRANS(vxor_vx, xors) 1638GEN_OPIVI_GVEC_TRANS(vand_vi, IMM_SX, vand_vx, andi) 1639GEN_OPIVI_GVEC_TRANS(vor_vi, IMM_SX, vor_vx, ori) 1640GEN_OPIVI_GVEC_TRANS(vxor_vi, IMM_SX, vxor_vx, xori) 1641 1642/* Vector Single-Width Bit Shift Instructions */ 1643GEN_OPIVV_GVEC_TRANS(vsll_vv, shlv) 1644GEN_OPIVV_GVEC_TRANS(vsrl_vv, shrv) 1645GEN_OPIVV_GVEC_TRANS(vsra_vv, sarv) 1646 1647typedef void GVecGen2sFn32(unsigned, uint32_t, uint32_t, TCGv_i32, 1648 uint32_t, uint32_t); 1649 1650static inline bool 1651do_opivx_gvec_shift(DisasContext *s, arg_rmrr *a, GVecGen2sFn32 *gvec_fn, 1652 gen_helper_opivx *fn) 1653{ 1654 if (!opivx_check(s, a)) { 1655 return false; 1656 } 1657 1658 if (a->vm && s->vl_eq_vlmax) { 1659 TCGv_i32 src1 = tcg_temp_new_i32(); 1660 1661 tcg_gen_trunc_tl_i32(src1, get_gpr(s, a->rs1, EXT_NONE)); 1662 tcg_gen_extract_i32(src1, src1, 0, s->sew + 3); 1663 gvec_fn(s->sew, vreg_ofs(s, a->rd), vreg_ofs(s, a->rs2), 1664 src1, MAXSZ(s), MAXSZ(s)); 1665 1666 tcg_temp_free_i32(src1); 1667 mark_vs_dirty(s); 1668 return true; 1669 } 1670 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s); 1671} 1672 1673#define GEN_OPIVX_GVEC_SHIFT_TRANS(NAME, SUF) \ 1674static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1675{ \ 1676 static gen_helper_opivx * const fns[4] = { \ 1677 gen_helper_##NAME##_b, gen_helper_##NAME##_h, \ 1678 gen_helper_##NAME##_w, gen_helper_##NAME##_d, \ 1679 }; \ 1680 \ 1681 return do_opivx_gvec_shift(s, a, tcg_gen_gvec_##SUF, fns[s->sew]); \ 1682} 1683 1684GEN_OPIVX_GVEC_SHIFT_TRANS(vsll_vx, shls) 1685GEN_OPIVX_GVEC_SHIFT_TRANS(vsrl_vx, shrs) 1686GEN_OPIVX_GVEC_SHIFT_TRANS(vsra_vx, sars) 1687 1688GEN_OPIVI_GVEC_TRANS(vsll_vi, IMM_ZX, vsll_vx, shli) 1689GEN_OPIVI_GVEC_TRANS(vsrl_vi, IMM_ZX, vsrl_vx, shri) 1690GEN_OPIVI_GVEC_TRANS(vsra_vi, IMM_ZX, vsra_vx, sari) 1691 1692/* Vector Narrowing Integer Right Shift Instructions */ 1693static bool opivv_narrow_check(DisasContext *s, arg_rmrr *a) 1694{ 1695 return require_rvv(s) && 1696 vext_check_isa_ill(s) && 1697 vext_check_sds(s, a->rd, a->rs1, a->rs2, a->vm); 1698} 1699 1700/* OPIVV with NARROW */ 1701#define GEN_OPIVV_NARROW_TRANS(NAME) \ 1702static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1703{ \ 1704 if (opivv_narrow_check(s, a)) { \ 1705 uint32_t data = 0; \ 1706 static gen_helper_gvec_4_ptr * const fns[3] = { \ 1707 gen_helper_##NAME##_b, \ 1708 gen_helper_##NAME##_h, \ 1709 gen_helper_##NAME##_w, \ 1710 }; \ 1711 TCGLabel *over = gen_new_label(); \ 1712 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 1713 \ 1714 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 1715 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 1716 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 1717 vreg_ofs(s, a->rs1), \ 1718 vreg_ofs(s, a->rs2), cpu_env, \ 1719 s->vlen / 8, s->vlen / 8, data, \ 1720 fns[s->sew]); \ 1721 mark_vs_dirty(s); \ 1722 gen_set_label(over); \ 1723 return true; \ 1724 } \ 1725 return false; \ 1726} 1727GEN_OPIVV_NARROW_TRANS(vnsra_vv) 1728GEN_OPIVV_NARROW_TRANS(vnsrl_vv) 1729 1730static bool opivx_narrow_check(DisasContext *s, arg_rmrr *a) 1731{ 1732 return require_rvv(s) && 1733 vext_check_isa_ill(s) && 1734 vext_check_sd(s, a->rd, a->rs2, a->vm); 1735} 1736 1737/* OPIVX with NARROW */ 1738#define GEN_OPIVX_NARROW_TRANS(NAME) \ 1739static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1740{ \ 1741 if (opivx_narrow_check(s, a)) { \ 1742 static gen_helper_opivx * const fns[3] = { \ 1743 gen_helper_##NAME##_b, \ 1744 gen_helper_##NAME##_h, \ 1745 gen_helper_##NAME##_w, \ 1746 }; \ 1747 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\ 1748 } \ 1749 return false; \ 1750} 1751 1752GEN_OPIVX_NARROW_TRANS(vnsra_vx) 1753GEN_OPIVX_NARROW_TRANS(vnsrl_vx) 1754 1755/* OPIVI with NARROW */ 1756#define GEN_OPIVI_NARROW_TRANS(NAME, IMM_MODE, OPIVX) \ 1757static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 1758{ \ 1759 if (opivx_narrow_check(s, a)) { \ 1760 static gen_helper_opivx * const fns[3] = { \ 1761 gen_helper_##OPIVX##_b, \ 1762 gen_helper_##OPIVX##_h, \ 1763 gen_helper_##OPIVX##_w, \ 1764 }; \ 1765 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \ 1766 fns[s->sew], s, IMM_MODE); \ 1767 } \ 1768 return false; \ 1769} 1770 1771GEN_OPIVI_NARROW_TRANS(vnsra_vi, IMM_ZX, vnsra_vx) 1772GEN_OPIVI_NARROW_TRANS(vnsrl_vi, IMM_ZX, vnsrl_vx) 1773 1774/* Vector Integer Comparison Instructions */ 1775/* 1776 * For all comparison instructions, an illegal instruction exception is raised 1777 * if the destination vector register overlaps a source vector register group 1778 * and LMUL > 1. 1779 */ 1780static bool opivv_cmp_check(DisasContext *s, arg_rmrr *a) 1781{ 1782 return require_rvv(s) && 1783 vext_check_isa_ill(s) && 1784 vext_check_mss(s, a->rd, a->rs1, a->rs2); 1785} 1786 1787GEN_OPIVV_TRANS(vmseq_vv, opivv_cmp_check) 1788GEN_OPIVV_TRANS(vmsne_vv, opivv_cmp_check) 1789GEN_OPIVV_TRANS(vmsltu_vv, opivv_cmp_check) 1790GEN_OPIVV_TRANS(vmslt_vv, opivv_cmp_check) 1791GEN_OPIVV_TRANS(vmsleu_vv, opivv_cmp_check) 1792GEN_OPIVV_TRANS(vmsle_vv, opivv_cmp_check) 1793 1794static bool opivx_cmp_check(DisasContext *s, arg_rmrr *a) 1795{ 1796 return require_rvv(s) && 1797 vext_check_isa_ill(s) && 1798 vext_check_ms(s, a->rd, a->rs2); 1799} 1800 1801GEN_OPIVX_TRANS(vmseq_vx, opivx_cmp_check) 1802GEN_OPIVX_TRANS(vmsne_vx, opivx_cmp_check) 1803GEN_OPIVX_TRANS(vmsltu_vx, opivx_cmp_check) 1804GEN_OPIVX_TRANS(vmslt_vx, opivx_cmp_check) 1805GEN_OPIVX_TRANS(vmsleu_vx, opivx_cmp_check) 1806GEN_OPIVX_TRANS(vmsle_vx, opivx_cmp_check) 1807GEN_OPIVX_TRANS(vmsgtu_vx, opivx_cmp_check) 1808GEN_OPIVX_TRANS(vmsgt_vx, opivx_cmp_check) 1809 1810GEN_OPIVI_TRANS(vmseq_vi, IMM_SX, vmseq_vx, opivx_cmp_check) 1811GEN_OPIVI_TRANS(vmsne_vi, IMM_SX, vmsne_vx, opivx_cmp_check) 1812GEN_OPIVI_TRANS(vmsleu_vi, IMM_ZX, vmsleu_vx, opivx_cmp_check) 1813GEN_OPIVI_TRANS(vmsle_vi, IMM_SX, vmsle_vx, opivx_cmp_check) 1814GEN_OPIVI_TRANS(vmsgtu_vi, IMM_ZX, vmsgtu_vx, opivx_cmp_check) 1815GEN_OPIVI_TRANS(vmsgt_vi, IMM_SX, vmsgt_vx, opivx_cmp_check) 1816 1817/* Vector Integer Min/Max Instructions */ 1818GEN_OPIVV_GVEC_TRANS(vminu_vv, umin) 1819GEN_OPIVV_GVEC_TRANS(vmin_vv, smin) 1820GEN_OPIVV_GVEC_TRANS(vmaxu_vv, umax) 1821GEN_OPIVV_GVEC_TRANS(vmax_vv, smax) 1822GEN_OPIVX_TRANS(vminu_vx, opivx_check) 1823GEN_OPIVX_TRANS(vmin_vx, opivx_check) 1824GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) 1825GEN_OPIVX_TRANS(vmax_vx, opivx_check) 1826 1827/* Vector Single-Width Integer Multiply Instructions */ 1828GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) 1829GEN_OPIVV_TRANS(vmulh_vv, opivv_check) 1830GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) 1831GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) 1832GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) 1833GEN_OPIVX_TRANS(vmulh_vx, opivx_check) 1834GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) 1835GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) 1836 1837/* Vector Integer Divide Instructions */ 1838GEN_OPIVV_TRANS(vdivu_vv, opivv_check) 1839GEN_OPIVV_TRANS(vdiv_vv, opivv_check) 1840GEN_OPIVV_TRANS(vremu_vv, opivv_check) 1841GEN_OPIVV_TRANS(vrem_vv, opivv_check) 1842GEN_OPIVX_TRANS(vdivu_vx, opivx_check) 1843GEN_OPIVX_TRANS(vdiv_vx, opivx_check) 1844GEN_OPIVX_TRANS(vremu_vx, opivx_check) 1845GEN_OPIVX_TRANS(vrem_vx, opivx_check) 1846 1847/* Vector Widening Integer Multiply Instructions */ 1848GEN_OPIVV_WIDEN_TRANS(vwmul_vv, opivv_widen_check) 1849GEN_OPIVV_WIDEN_TRANS(vwmulu_vv, opivv_widen_check) 1850GEN_OPIVV_WIDEN_TRANS(vwmulsu_vv, opivv_widen_check) 1851GEN_OPIVX_WIDEN_TRANS(vwmul_vx) 1852GEN_OPIVX_WIDEN_TRANS(vwmulu_vx) 1853GEN_OPIVX_WIDEN_TRANS(vwmulsu_vx) 1854 1855/* Vector Single-Width Integer Multiply-Add Instructions */ 1856GEN_OPIVV_TRANS(vmacc_vv, opivv_check) 1857GEN_OPIVV_TRANS(vnmsac_vv, opivv_check) 1858GEN_OPIVV_TRANS(vmadd_vv, opivv_check) 1859GEN_OPIVV_TRANS(vnmsub_vv, opivv_check) 1860GEN_OPIVX_TRANS(vmacc_vx, opivx_check) 1861GEN_OPIVX_TRANS(vnmsac_vx, opivx_check) 1862GEN_OPIVX_TRANS(vmadd_vx, opivx_check) 1863GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) 1864 1865/* Vector Widening Integer Multiply-Add Instructions */ 1866GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) 1867GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) 1868GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) 1869GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx) 1870GEN_OPIVX_WIDEN_TRANS(vwmacc_vx) 1871GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx) 1872GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx) 1873 1874/* Vector Integer Merge and Move Instructions */ 1875static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) 1876{ 1877 if (require_rvv(s) && 1878 vext_check_isa_ill(s) && 1879 /* vmv.v.v has rs2 = 0 and vm = 1 */ 1880 vext_check_sss(s, a->rd, a->rs1, 0, 1)) { 1881 if (s->vl_eq_vlmax) { 1882 tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), 1883 vreg_ofs(s, a->rs1), 1884 MAXSZ(s), MAXSZ(s)); 1885 } else { 1886 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1887 static gen_helper_gvec_2_ptr * const fns[4] = { 1888 gen_helper_vmv_v_v_b, gen_helper_vmv_v_v_h, 1889 gen_helper_vmv_v_v_w, gen_helper_vmv_v_v_d, 1890 }; 1891 TCGLabel *over = gen_new_label(); 1892 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1893 1894 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), 1895 cpu_env, s->vlen / 8, s->vlen / 8, data, 1896 fns[s->sew]); 1897 gen_set_label(over); 1898 } 1899 mark_vs_dirty(s); 1900 return true; 1901 } 1902 return false; 1903} 1904 1905typedef void gen_helper_vmv_vx(TCGv_ptr, TCGv_i64, TCGv_env, TCGv_i32); 1906static bool trans_vmv_v_x(DisasContext *s, arg_vmv_v_x *a) 1907{ 1908 if (require_rvv(s) && 1909 vext_check_isa_ill(s) && 1910 /* vmv.v.x has rs2 = 0 and vm = 1 */ 1911 vext_check_ss(s, a->rd, 0, 1)) { 1912 TCGv s1; 1913 TCGLabel *over = gen_new_label(); 1914 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1915 1916 s1 = get_gpr(s, a->rs1, EXT_SIGN); 1917 1918 if (s->vl_eq_vlmax) { 1919 tcg_gen_gvec_dup_tl(s->sew, vreg_ofs(s, a->rd), 1920 MAXSZ(s), MAXSZ(s), s1); 1921 } else { 1922 TCGv_i32 desc; 1923 TCGv_i64 s1_i64 = tcg_temp_new_i64(); 1924 TCGv_ptr dest = tcg_temp_new_ptr(); 1925 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1926 static gen_helper_vmv_vx * const fns[4] = { 1927 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1928 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1929 }; 1930 1931 tcg_gen_ext_tl_i64(s1_i64, s1); 1932 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1933 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1934 fns[s->sew](dest, s1_i64, cpu_env, desc); 1935 1936 tcg_temp_free_ptr(dest); 1937 tcg_temp_free_i64(s1_i64); 1938 } 1939 1940 mark_vs_dirty(s); 1941 gen_set_label(over); 1942 return true; 1943 } 1944 return false; 1945} 1946 1947static bool trans_vmv_v_i(DisasContext *s, arg_vmv_v_i *a) 1948{ 1949 if (require_rvv(s) && 1950 vext_check_isa_ill(s) && 1951 /* vmv.v.i has rs2 = 0 and vm = 1 */ 1952 vext_check_ss(s, a->rd, 0, 1)) { 1953 int64_t simm = sextract64(a->rs1, 0, 5); 1954 if (s->vl_eq_vlmax) { 1955 tcg_gen_gvec_dup_imm(s->sew, vreg_ofs(s, a->rd), 1956 MAXSZ(s), MAXSZ(s), simm); 1957 mark_vs_dirty(s); 1958 } else { 1959 TCGv_i32 desc; 1960 TCGv_i64 s1; 1961 TCGv_ptr dest; 1962 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 1963 static gen_helper_vmv_vx * const fns[4] = { 1964 gen_helper_vmv_v_x_b, gen_helper_vmv_v_x_h, 1965 gen_helper_vmv_v_x_w, gen_helper_vmv_v_x_d, 1966 }; 1967 TCGLabel *over = gen_new_label(); 1968 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 1969 1970 s1 = tcg_constant_i64(simm); 1971 dest = tcg_temp_new_ptr(); 1972 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 1973 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 1974 fns[s->sew](dest, s1, cpu_env, desc); 1975 1976 tcg_temp_free_ptr(dest); 1977 mark_vs_dirty(s); 1978 gen_set_label(over); 1979 } 1980 return true; 1981 } 1982 return false; 1983} 1984 1985GEN_OPIVV_TRANS(vmerge_vvm, opivv_vadc_check) 1986GEN_OPIVX_TRANS(vmerge_vxm, opivx_vadc_check) 1987GEN_OPIVI_TRANS(vmerge_vim, IMM_SX, vmerge_vxm, opivx_vadc_check) 1988 1989/* 1990 *** Vector Fixed-Point Arithmetic Instructions 1991 */ 1992 1993/* Vector Single-Width Saturating Add and Subtract */ 1994GEN_OPIVV_TRANS(vsaddu_vv, opivv_check) 1995GEN_OPIVV_TRANS(vsadd_vv, opivv_check) 1996GEN_OPIVV_TRANS(vssubu_vv, opivv_check) 1997GEN_OPIVV_TRANS(vssub_vv, opivv_check) 1998GEN_OPIVX_TRANS(vsaddu_vx, opivx_check) 1999GEN_OPIVX_TRANS(vsadd_vx, opivx_check) 2000GEN_OPIVX_TRANS(vssubu_vx, opivx_check) 2001GEN_OPIVX_TRANS(vssub_vx, opivx_check) 2002GEN_OPIVI_TRANS(vsaddu_vi, IMM_ZX, vsaddu_vx, opivx_check) 2003GEN_OPIVI_TRANS(vsadd_vi, IMM_SX, vsadd_vx, opivx_check) 2004 2005/* Vector Single-Width Averaging Add and Subtract */ 2006GEN_OPIVV_TRANS(vaadd_vv, opivv_check) 2007GEN_OPIVV_TRANS(vasub_vv, opivv_check) 2008GEN_OPIVX_TRANS(vaadd_vx, opivx_check) 2009GEN_OPIVX_TRANS(vasub_vx, opivx_check) 2010GEN_OPIVI_TRANS(vaadd_vi, 0, vaadd_vx, opivx_check) 2011 2012/* Vector Single-Width Fractional Multiply with Rounding and Saturation */ 2013GEN_OPIVV_TRANS(vsmul_vv, opivv_check) 2014GEN_OPIVX_TRANS(vsmul_vx, opivx_check) 2015 2016/* Vector Widening Saturating Scaled Multiply-Add */ 2017GEN_OPIVV_WIDEN_TRANS(vwsmaccu_vv, opivv_widen_check) 2018GEN_OPIVV_WIDEN_TRANS(vwsmacc_vv, opivv_widen_check) 2019GEN_OPIVV_WIDEN_TRANS(vwsmaccsu_vv, opivv_widen_check) 2020GEN_OPIVX_WIDEN_TRANS(vwsmaccu_vx) 2021GEN_OPIVX_WIDEN_TRANS(vwsmacc_vx) 2022GEN_OPIVX_WIDEN_TRANS(vwsmaccsu_vx) 2023GEN_OPIVX_WIDEN_TRANS(vwsmaccus_vx) 2024 2025/* Vector Single-Width Scaling Shift Instructions */ 2026GEN_OPIVV_TRANS(vssrl_vv, opivv_check) 2027GEN_OPIVV_TRANS(vssra_vv, opivv_check) 2028GEN_OPIVX_TRANS(vssrl_vx, opivx_check) 2029GEN_OPIVX_TRANS(vssra_vx, opivx_check) 2030GEN_OPIVI_TRANS(vssrl_vi, IMM_ZX, vssrl_vx, opivx_check) 2031GEN_OPIVI_TRANS(vssra_vi, IMM_SX, vssra_vx, opivx_check) 2032 2033/* Vector Narrowing Fixed-Point Clip Instructions */ 2034GEN_OPIVV_NARROW_TRANS(vnclipu_vv) 2035GEN_OPIVV_NARROW_TRANS(vnclip_vv) 2036GEN_OPIVX_NARROW_TRANS(vnclipu_vx) 2037GEN_OPIVX_NARROW_TRANS(vnclip_vx) 2038GEN_OPIVI_NARROW_TRANS(vnclipu_vi, IMM_ZX, vnclipu_vx) 2039GEN_OPIVI_NARROW_TRANS(vnclip_vi, IMM_ZX, vnclip_vx) 2040 2041/* 2042 *** Vector Float Point Arithmetic Instructions 2043 */ 2044 2045/* 2046 * As RVF-only cpus always have values NaN-boxed to 64-bits, 2047 * RVF and RVD can be treated equally. 2048 * We don't have to deal with the cases of: SEW > FLEN. 2049 * 2050 * If SEW < FLEN, check whether input fp register is a valid 2051 * NaN-boxed value, in which case the least-significant SEW bits 2052 * of the f regsiter are used, else the canonical NaN value is used. 2053 */ 2054static void do_nanbox(DisasContext *s, TCGv_i64 out, TCGv_i64 in) 2055{ 2056 switch (s->sew) { 2057 case 1: 2058 gen_check_nanbox_h(out, in); 2059 break; 2060 case 2: 2061 gen_check_nanbox_s(out, in); 2062 break; 2063 case 3: 2064 tcg_gen_mov_i64(out, in); 2065 break; 2066 default: 2067 g_assert_not_reached(); 2068 } 2069} 2070 2071/* Vector Single-Width Floating-Point Add/Subtract Instructions */ 2072 2073/* 2074 * If the current SEW does not correspond to a supported IEEE floating-point 2075 * type, an illegal instruction exception is raised. 2076 */ 2077static bool opfvv_check(DisasContext *s, arg_rmrr *a) 2078{ 2079 return require_rvv(s) && 2080 require_rvf(s) && 2081 vext_check_isa_ill(s) && 2082 vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); 2083} 2084 2085/* OPFVV without GVEC IR */ 2086#define GEN_OPFVV_TRANS(NAME, CHECK) \ 2087static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2088{ \ 2089 if (CHECK(s, a)) { \ 2090 uint32_t data = 0; \ 2091 static gen_helper_gvec_4_ptr * const fns[3] = { \ 2092 gen_helper_##NAME##_h, \ 2093 gen_helper_##NAME##_w, \ 2094 gen_helper_##NAME##_d, \ 2095 }; \ 2096 TCGLabel *over = gen_new_label(); \ 2097 gen_set_rm(s, 7); \ 2098 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2099 \ 2100 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2101 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2102 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2103 vreg_ofs(s, a->rs1), \ 2104 vreg_ofs(s, a->rs2), cpu_env, \ 2105 s->vlen / 8, s->vlen / 8, data, \ 2106 fns[s->sew - 1]); \ 2107 mark_vs_dirty(s); \ 2108 gen_set_label(over); \ 2109 return true; \ 2110 } \ 2111 return false; \ 2112} 2113GEN_OPFVV_TRANS(vfadd_vv, opfvv_check) 2114GEN_OPFVV_TRANS(vfsub_vv, opfvv_check) 2115 2116typedef void gen_helper_opfvf(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, 2117 TCGv_env, TCGv_i32); 2118 2119static bool opfvf_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, 2120 uint32_t data, gen_helper_opfvf *fn, DisasContext *s) 2121{ 2122 TCGv_ptr dest, src2, mask; 2123 TCGv_i32 desc; 2124 TCGv_i64 t1; 2125 2126 TCGLabel *over = gen_new_label(); 2127 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2128 2129 dest = tcg_temp_new_ptr(); 2130 mask = tcg_temp_new_ptr(); 2131 src2 = tcg_temp_new_ptr(); 2132 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2133 2134 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, vd)); 2135 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, vs2)); 2136 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2137 2138 /* NaN-box f[rs1] */ 2139 t1 = tcg_temp_new_i64(); 2140 do_nanbox(s, t1, cpu_fpr[rs1]); 2141 2142 fn(dest, mask, t1, src2, cpu_env, desc); 2143 2144 tcg_temp_free_ptr(dest); 2145 tcg_temp_free_ptr(mask); 2146 tcg_temp_free_ptr(src2); 2147 tcg_temp_free_i64(t1); 2148 mark_vs_dirty(s); 2149 gen_set_label(over); 2150 return true; 2151} 2152 2153/* 2154 * If the current SEW does not correspond to a supported IEEE floating-point 2155 * type, an illegal instruction exception is raised 2156 */ 2157static bool opfvf_check(DisasContext *s, arg_rmrr *a) 2158{ 2159 return require_rvv(s) && 2160 require_rvf(s) && 2161 vext_check_isa_ill(s) && 2162 vext_check_ss(s, a->rd, a->rs2, a->vm); 2163} 2164 2165/* OPFVF without GVEC IR */ 2166#define GEN_OPFVF_TRANS(NAME, CHECK) \ 2167static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2168{ \ 2169 if (CHECK(s, a)) { \ 2170 uint32_t data = 0; \ 2171 static gen_helper_opfvf *const fns[3] = { \ 2172 gen_helper_##NAME##_h, \ 2173 gen_helper_##NAME##_w, \ 2174 gen_helper_##NAME##_d, \ 2175 }; \ 2176 gen_set_rm(s, 7); \ 2177 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2178 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2179 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2180 fns[s->sew - 1], s); \ 2181 } \ 2182 return false; \ 2183} 2184 2185GEN_OPFVF_TRANS(vfadd_vf, opfvf_check) 2186GEN_OPFVF_TRANS(vfsub_vf, opfvf_check) 2187GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) 2188 2189/* Vector Widening Floating-Point Add/Subtract Instructions */ 2190static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) 2191{ 2192 return require_rvv(s) && 2193 require_rvf(s) && 2194 vext_check_isa_ill(s) && 2195 vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); 2196} 2197 2198/* OPFVV with WIDEN */ 2199#define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ 2200static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2201{ \ 2202 if (CHECK(s, a)) { \ 2203 uint32_t data = 0; \ 2204 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2205 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2206 }; \ 2207 TCGLabel *over = gen_new_label(); \ 2208 gen_set_rm(s, 7); \ 2209 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2210 \ 2211 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2212 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2213 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2214 vreg_ofs(s, a->rs1), \ 2215 vreg_ofs(s, a->rs2), cpu_env, \ 2216 s->vlen / 8, s->vlen / 8, data, \ 2217 fns[s->sew - 1]); \ 2218 mark_vs_dirty(s); \ 2219 gen_set_label(over); \ 2220 return true; \ 2221 } \ 2222 return false; \ 2223} 2224 2225GEN_OPFVV_WIDEN_TRANS(vfwadd_vv, opfvv_widen_check) 2226GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) 2227 2228static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) 2229{ 2230 return require_rvv(s) && 2231 require_rvf(s) && 2232 vext_check_isa_ill(s) && 2233 vext_check_ds(s, a->rd, a->rs2, a->vm); 2234} 2235 2236/* OPFVF with WIDEN */ 2237#define GEN_OPFVF_WIDEN_TRANS(NAME) \ 2238static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2239{ \ 2240 if (opfvf_widen_check(s, a)) { \ 2241 uint32_t data = 0; \ 2242 static gen_helper_opfvf *const fns[2] = { \ 2243 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2244 }; \ 2245 gen_set_rm(s, 7); \ 2246 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2247 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2248 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2249 fns[s->sew - 1], s); \ 2250 } \ 2251 return false; \ 2252} 2253 2254GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) 2255GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) 2256 2257static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) 2258{ 2259 return require_rvv(s) && 2260 require_rvf(s) && 2261 vext_check_isa_ill(s) && 2262 vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); 2263} 2264 2265/* WIDEN OPFVV with WIDEN */ 2266#define GEN_OPFWV_WIDEN_TRANS(NAME) \ 2267static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2268{ \ 2269 if (opfwv_widen_check(s, a)) { \ 2270 uint32_t data = 0; \ 2271 static gen_helper_gvec_4_ptr * const fns[2] = { \ 2272 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2273 }; \ 2274 TCGLabel *over = gen_new_label(); \ 2275 gen_set_rm(s, 7); \ 2276 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2277 \ 2278 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2279 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2280 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2281 vreg_ofs(s, a->rs1), \ 2282 vreg_ofs(s, a->rs2), cpu_env, \ 2283 s->vlen / 8, s->vlen / 8, data, \ 2284 fns[s->sew - 1]); \ 2285 mark_vs_dirty(s); \ 2286 gen_set_label(over); \ 2287 return true; \ 2288 } \ 2289 return false; \ 2290} 2291 2292GEN_OPFWV_WIDEN_TRANS(vfwadd_wv) 2293GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) 2294 2295static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) 2296{ 2297 return require_rvv(s) && 2298 require_rvf(s) && 2299 vext_check_isa_ill(s) && 2300 vext_check_dd(s, a->rd, a->rs2, a->vm); 2301} 2302 2303/* WIDEN OPFVF with WIDEN */ 2304#define GEN_OPFWF_WIDEN_TRANS(NAME) \ 2305static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ 2306{ \ 2307 if (opfwf_widen_check(s, a)) { \ 2308 uint32_t data = 0; \ 2309 static gen_helper_opfvf *const fns[2] = { \ 2310 gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ 2311 }; \ 2312 gen_set_rm(s, 7); \ 2313 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2314 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2315 return opfvf_trans(a->rd, a->rs1, a->rs2, data, \ 2316 fns[s->sew - 1], s); \ 2317 } \ 2318 return false; \ 2319} 2320 2321GEN_OPFWF_WIDEN_TRANS(vfwadd_wf) 2322GEN_OPFWF_WIDEN_TRANS(vfwsub_wf) 2323 2324/* Vector Single-Width Floating-Point Multiply/Divide Instructions */ 2325GEN_OPFVV_TRANS(vfmul_vv, opfvv_check) 2326GEN_OPFVV_TRANS(vfdiv_vv, opfvv_check) 2327GEN_OPFVF_TRANS(vfmul_vf, opfvf_check) 2328GEN_OPFVF_TRANS(vfdiv_vf, opfvf_check) 2329GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) 2330 2331/* Vector Widening Floating-Point Multiply */ 2332GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) 2333GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) 2334 2335/* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ 2336GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) 2337GEN_OPFVV_TRANS(vfnmacc_vv, opfvv_check) 2338GEN_OPFVV_TRANS(vfmsac_vv, opfvv_check) 2339GEN_OPFVV_TRANS(vfnmsac_vv, opfvv_check) 2340GEN_OPFVV_TRANS(vfmadd_vv, opfvv_check) 2341GEN_OPFVV_TRANS(vfnmadd_vv, opfvv_check) 2342GEN_OPFVV_TRANS(vfmsub_vv, opfvv_check) 2343GEN_OPFVV_TRANS(vfnmsub_vv, opfvv_check) 2344GEN_OPFVF_TRANS(vfmacc_vf, opfvf_check) 2345GEN_OPFVF_TRANS(vfnmacc_vf, opfvf_check) 2346GEN_OPFVF_TRANS(vfmsac_vf, opfvf_check) 2347GEN_OPFVF_TRANS(vfnmsac_vf, opfvf_check) 2348GEN_OPFVF_TRANS(vfmadd_vf, opfvf_check) 2349GEN_OPFVF_TRANS(vfnmadd_vf, opfvf_check) 2350GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) 2351GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) 2352 2353/* Vector Widening Floating-Point Fused Multiply-Add Instructions */ 2354GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) 2355GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) 2356GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) 2357GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) 2358GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) 2359GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) 2360GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) 2361GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) 2362 2363/* Vector Floating-Point Square-Root Instruction */ 2364 2365/* 2366 * If the current SEW does not correspond to a supported IEEE floating-point 2367 * type, an illegal instruction exception is raised 2368 */ 2369static bool opfv_check(DisasContext *s, arg_rmr *a) 2370{ 2371 return require_rvv(s) && 2372 require_rvf(s) && 2373 vext_check_isa_ill(s) && 2374 /* OPFV instructions ignore vs1 check */ 2375 vext_check_ss(s, a->rd, a->rs2, a->vm); 2376} 2377 2378#define GEN_OPFV_TRANS(NAME, CHECK) \ 2379static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2380{ \ 2381 if (CHECK(s, a)) { \ 2382 uint32_t data = 0; \ 2383 static gen_helper_gvec_3_ptr * const fns[3] = { \ 2384 gen_helper_##NAME##_h, \ 2385 gen_helper_##NAME##_w, \ 2386 gen_helper_##NAME##_d, \ 2387 }; \ 2388 TCGLabel *over = gen_new_label(); \ 2389 gen_set_rm(s, 7); \ 2390 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2391 \ 2392 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2393 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2394 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2395 vreg_ofs(s, a->rs2), cpu_env, \ 2396 s->vlen / 8, s->vlen / 8, data, \ 2397 fns[s->sew - 1]); \ 2398 mark_vs_dirty(s); \ 2399 gen_set_label(over); \ 2400 return true; \ 2401 } \ 2402 return false; \ 2403} 2404 2405GEN_OPFV_TRANS(vfsqrt_v, opfv_check) 2406 2407/* Vector Floating-Point MIN/MAX Instructions */ 2408GEN_OPFVV_TRANS(vfmin_vv, opfvv_check) 2409GEN_OPFVV_TRANS(vfmax_vv, opfvv_check) 2410GEN_OPFVF_TRANS(vfmin_vf, opfvf_check) 2411GEN_OPFVF_TRANS(vfmax_vf, opfvf_check) 2412 2413/* Vector Floating-Point Sign-Injection Instructions */ 2414GEN_OPFVV_TRANS(vfsgnj_vv, opfvv_check) 2415GEN_OPFVV_TRANS(vfsgnjn_vv, opfvv_check) 2416GEN_OPFVV_TRANS(vfsgnjx_vv, opfvv_check) 2417GEN_OPFVF_TRANS(vfsgnj_vf, opfvf_check) 2418GEN_OPFVF_TRANS(vfsgnjn_vf, opfvf_check) 2419GEN_OPFVF_TRANS(vfsgnjx_vf, opfvf_check) 2420 2421/* Vector Floating-Point Compare Instructions */ 2422static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) 2423{ 2424 return require_rvv(s) && 2425 require_rvf(s) && 2426 vext_check_isa_ill(s) && 2427 vext_check_mss(s, a->rd, a->rs1, a->rs2); 2428} 2429 2430GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) 2431GEN_OPFVV_TRANS(vmfne_vv, opfvv_cmp_check) 2432GEN_OPFVV_TRANS(vmflt_vv, opfvv_cmp_check) 2433GEN_OPFVV_TRANS(vmfle_vv, opfvv_cmp_check) 2434GEN_OPFVV_TRANS(vmford_vv, opfvv_cmp_check) 2435 2436static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) 2437{ 2438 return require_rvv(s) && 2439 require_rvf(s) && 2440 vext_check_isa_ill(s) && 2441 vext_check_ms(s, a->rd, a->rs2); 2442} 2443 2444GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) 2445GEN_OPFVF_TRANS(vmfne_vf, opfvf_cmp_check) 2446GEN_OPFVF_TRANS(vmflt_vf, opfvf_cmp_check) 2447GEN_OPFVF_TRANS(vmfle_vf, opfvf_cmp_check) 2448GEN_OPFVF_TRANS(vmfgt_vf, opfvf_cmp_check) 2449GEN_OPFVF_TRANS(vmfge_vf, opfvf_cmp_check) 2450GEN_OPFVF_TRANS(vmford_vf, opfvf_cmp_check) 2451 2452/* Vector Floating-Point Classify Instruction */ 2453GEN_OPFV_TRANS(vfclass_v, opfv_check) 2454 2455/* Vector Floating-Point Merge Instruction */ 2456GEN_OPFVF_TRANS(vfmerge_vfm, opfvf_check) 2457 2458static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) 2459{ 2460 if (require_rvv(s) && 2461 require_rvf(s) && 2462 vext_check_isa_ill(s) && 2463 require_align(a->rd, s->lmul)) { 2464 if (s->vl_eq_vlmax) { 2465 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 2466 MAXSZ(s), MAXSZ(s), cpu_fpr[a->rs1]); 2467 mark_vs_dirty(s); 2468 } else { 2469 TCGv_ptr dest; 2470 TCGv_i32 desc; 2471 uint32_t data = FIELD_DP32(0, VDATA, LMUL, s->lmul); 2472 static gen_helper_vmv_vx * const fns[3] = { 2473 gen_helper_vmv_v_x_h, 2474 gen_helper_vmv_v_x_w, 2475 gen_helper_vmv_v_x_d, 2476 }; 2477 TCGLabel *over = gen_new_label(); 2478 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2479 2480 dest = tcg_temp_new_ptr(); 2481 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2482 tcg_gen_addi_ptr(dest, cpu_env, vreg_ofs(s, a->rd)); 2483 fns[s->sew - 1](dest, cpu_fpr[a->rs1], cpu_env, desc); 2484 2485 tcg_temp_free_ptr(dest); 2486 mark_vs_dirty(s); 2487 gen_set_label(over); 2488 } 2489 return true; 2490 } 2491 return false; 2492} 2493 2494/* Single-Width Floating-Point/Integer Type-Convert Instructions */ 2495GEN_OPFV_TRANS(vfcvt_xu_f_v, opfv_check) 2496GEN_OPFV_TRANS(vfcvt_x_f_v, opfv_check) 2497GEN_OPFV_TRANS(vfcvt_f_xu_v, opfv_check) 2498GEN_OPFV_TRANS(vfcvt_f_x_v, opfv_check) 2499 2500/* Widening Floating-Point/Integer Type-Convert Instructions */ 2501 2502/* 2503 * If the current SEW does not correspond to a supported IEEE floating-point 2504 * type, an illegal instruction exception is raised 2505 */ 2506static bool opfv_widen_check(DisasContext *s, arg_rmr *a) 2507{ 2508 return require_rvv(s) && 2509 require_scale_rvf(s) && 2510 (s->sew != MO_8) && 2511 vext_check_isa_ill(s) && 2512 vext_check_ds(s, a->rd, a->rs2, a->vm); 2513} 2514 2515#define GEN_OPFV_WIDEN_TRANS(NAME) \ 2516static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2517{ \ 2518 if (opfv_widen_check(s, a)) { \ 2519 uint32_t data = 0; \ 2520 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2521 gen_helper_##NAME##_h, \ 2522 gen_helper_##NAME##_w, \ 2523 }; \ 2524 TCGLabel *over = gen_new_label(); \ 2525 gen_set_rm(s, 7); \ 2526 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2527 \ 2528 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2529 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2530 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2531 vreg_ofs(s, a->rs2), cpu_env, \ 2532 s->vlen / 8, s->vlen / 8, data, \ 2533 fns[s->sew - 1]); \ 2534 mark_vs_dirty(s); \ 2535 gen_set_label(over); \ 2536 return true; \ 2537 } \ 2538 return false; \ 2539} 2540 2541GEN_OPFV_WIDEN_TRANS(vfwcvt_xu_f_v) 2542GEN_OPFV_WIDEN_TRANS(vfwcvt_x_f_v) 2543GEN_OPFV_WIDEN_TRANS(vfwcvt_f_xu_v) 2544GEN_OPFV_WIDEN_TRANS(vfwcvt_f_x_v) 2545GEN_OPFV_WIDEN_TRANS(vfwcvt_f_f_v) 2546 2547/* Narrowing Floating-Point/Integer Type-Convert Instructions */ 2548 2549/* 2550 * If the current SEW does not correspond to a supported IEEE floating-point 2551 * type, an illegal instruction exception is raised 2552 */ 2553static bool opfv_narrow_check(DisasContext *s, arg_rmr *a) 2554{ 2555 return require_rvv(s) && 2556 require_rvf(s) && 2557 (s->sew != MO_64) && 2558 vext_check_isa_ill(s) && 2559 /* OPFV narrowing instructions ignore vs1 check */ 2560 vext_check_sd(s, a->rd, a->rs2, a->vm); 2561} 2562 2563#define GEN_OPFV_NARROW_TRANS(NAME) \ 2564static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2565{ \ 2566 if (opfv_narrow_check(s, a)) { \ 2567 uint32_t data = 0; \ 2568 static gen_helper_gvec_3_ptr * const fns[2] = { \ 2569 gen_helper_##NAME##_h, \ 2570 gen_helper_##NAME##_w, \ 2571 }; \ 2572 TCGLabel *over = gen_new_label(); \ 2573 gen_set_rm(s, 7); \ 2574 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2575 \ 2576 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2577 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2578 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2579 vreg_ofs(s, a->rs2), cpu_env, \ 2580 s->vlen / 8, s->vlen / 8, data, \ 2581 fns[s->sew - 1]); \ 2582 mark_vs_dirty(s); \ 2583 gen_set_label(over); \ 2584 return true; \ 2585 } \ 2586 return false; \ 2587} 2588 2589GEN_OPFV_NARROW_TRANS(vfncvt_xu_f_v) 2590GEN_OPFV_NARROW_TRANS(vfncvt_x_f_v) 2591GEN_OPFV_NARROW_TRANS(vfncvt_f_xu_v) 2592GEN_OPFV_NARROW_TRANS(vfncvt_f_x_v) 2593GEN_OPFV_NARROW_TRANS(vfncvt_f_f_v) 2594 2595/* 2596 *** Vector Reduction Operations 2597 */ 2598/* Vector Single-Width Integer Reduction Instructions */ 2599static bool reduction_check(DisasContext *s, arg_rmrr *a) 2600{ 2601 return require_rvv(s) && 2602 vext_check_isa_ill(s) && 2603 vext_check_reduction(s, a->rs2); 2604} 2605 2606GEN_OPIVV_TRANS(vredsum_vs, reduction_check) 2607GEN_OPIVV_TRANS(vredmaxu_vs, reduction_check) 2608GEN_OPIVV_TRANS(vredmax_vs, reduction_check) 2609GEN_OPIVV_TRANS(vredminu_vs, reduction_check) 2610GEN_OPIVV_TRANS(vredmin_vs, reduction_check) 2611GEN_OPIVV_TRANS(vredand_vs, reduction_check) 2612GEN_OPIVV_TRANS(vredor_vs, reduction_check) 2613GEN_OPIVV_TRANS(vredxor_vs, reduction_check) 2614 2615/* Vector Widening Integer Reduction Instructions */ 2616static bool reduction_widen_check(DisasContext *s, arg_rmrr *a) 2617{ 2618 return reduction_check(s, a) && (s->sew < MO_64); 2619} 2620 2621GEN_OPIVV_WIDEN_TRANS(vwredsum_vs, reduction_widen_check) 2622GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) 2623 2624/* Vector Single-Width Floating-Point Reduction Instructions */ 2625GEN_OPFVV_TRANS(vfredsum_vs, reduction_check) 2626GEN_OPFVV_TRANS(vfredmax_vs, reduction_check) 2627GEN_OPFVV_TRANS(vfredmin_vs, reduction_check) 2628 2629/* Vector Widening Floating-Point Reduction Instructions */ 2630GEN_OPFVV_WIDEN_TRANS(vfwredsum_vs, reduction_check) 2631 2632/* 2633 *** Vector Mask Operations 2634 */ 2635 2636/* Vector Mask-Register Logical Instructions */ 2637#define GEN_MM_TRANS(NAME) \ 2638static bool trans_##NAME(DisasContext *s, arg_r *a) \ 2639{ \ 2640 if (vext_check_isa_ill(s)) { \ 2641 uint32_t data = 0; \ 2642 gen_helper_gvec_4_ptr *fn = gen_helper_##NAME; \ 2643 TCGLabel *over = gen_new_label(); \ 2644 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2645 \ 2646 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2647 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \ 2648 vreg_ofs(s, a->rs1), \ 2649 vreg_ofs(s, a->rs2), cpu_env, \ 2650 s->vlen / 8, s->vlen / 8, data, fn); \ 2651 mark_vs_dirty(s); \ 2652 gen_set_label(over); \ 2653 return true; \ 2654 } \ 2655 return false; \ 2656} 2657 2658GEN_MM_TRANS(vmand_mm) 2659GEN_MM_TRANS(vmnand_mm) 2660GEN_MM_TRANS(vmandnot_mm) 2661GEN_MM_TRANS(vmxor_mm) 2662GEN_MM_TRANS(vmor_mm) 2663GEN_MM_TRANS(vmnor_mm) 2664GEN_MM_TRANS(vmornot_mm) 2665GEN_MM_TRANS(vmxnor_mm) 2666 2667/* Vector count population in mask vcpop */ 2668static bool trans_vcpop_m(DisasContext *s, arg_rmr *a) 2669{ 2670 if (require_rvv(s) && 2671 vext_check_isa_ill(s)) { 2672 TCGv_ptr src2, mask; 2673 TCGv dst; 2674 TCGv_i32 desc; 2675 uint32_t data = 0; 2676 data = FIELD_DP32(data, VDATA, VM, a->vm); 2677 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2678 2679 mask = tcg_temp_new_ptr(); 2680 src2 = tcg_temp_new_ptr(); 2681 dst = dest_gpr(s, a->rd); 2682 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2683 2684 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2685 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2686 2687 gen_helper_vcpop_m(dst, mask, src2, cpu_env, desc); 2688 gen_set_gpr(s, a->rd, dst); 2689 2690 tcg_temp_free_ptr(mask); 2691 tcg_temp_free_ptr(src2); 2692 2693 return true; 2694 } 2695 return false; 2696} 2697 2698/* vmfirst find-first-set mask bit */ 2699static bool trans_vfirst_m(DisasContext *s, arg_rmr *a) 2700{ 2701 if (require_rvv(s) && 2702 vext_check_isa_ill(s)) { 2703 TCGv_ptr src2, mask; 2704 TCGv dst; 2705 TCGv_i32 desc; 2706 uint32_t data = 0; 2707 data = FIELD_DP32(data, VDATA, VM, a->vm); 2708 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2709 2710 mask = tcg_temp_new_ptr(); 2711 src2 = tcg_temp_new_ptr(); 2712 dst = dest_gpr(s, a->rd); 2713 desc = tcg_constant_i32(simd_desc(s->vlen / 8, s->vlen / 8, data)); 2714 2715 tcg_gen_addi_ptr(src2, cpu_env, vreg_ofs(s, a->rs2)); 2716 tcg_gen_addi_ptr(mask, cpu_env, vreg_ofs(s, 0)); 2717 2718 gen_helper_vfirst_m(dst, mask, src2, cpu_env, desc); 2719 gen_set_gpr(s, a->rd, dst); 2720 2721 tcg_temp_free_ptr(mask); 2722 tcg_temp_free_ptr(src2); 2723 return true; 2724 } 2725 return false; 2726} 2727 2728/* vmsbf.m set-before-first mask bit */ 2729/* vmsif.m set-includ-first mask bit */ 2730/* vmsof.m set-only-first mask bit */ 2731#define GEN_M_TRANS(NAME) \ 2732static bool trans_##NAME(DisasContext *s, arg_rmr *a) \ 2733{ \ 2734 if (require_rvv(s) && \ 2735 vext_check_isa_ill(s) && \ 2736 require_vm(a->vm, a->rd) && \ 2737 (a->rd != a->rs2)) { \ 2738 uint32_t data = 0; \ 2739 gen_helper_gvec_3_ptr *fn = gen_helper_##NAME; \ 2740 TCGLabel *over = gen_new_label(); \ 2741 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \ 2742 \ 2743 data = FIELD_DP32(data, VDATA, VM, a->vm); \ 2744 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \ 2745 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), \ 2746 vreg_ofs(s, 0), vreg_ofs(s, a->rs2), \ 2747 cpu_env, s->vlen / 8, s->vlen / 8, \ 2748 data, fn); \ 2749 mark_vs_dirty(s); \ 2750 gen_set_label(over); \ 2751 return true; \ 2752 } \ 2753 return false; \ 2754} 2755 2756GEN_M_TRANS(vmsbf_m) 2757GEN_M_TRANS(vmsif_m) 2758GEN_M_TRANS(vmsof_m) 2759 2760/* 2761 * Vector Iota Instruction 2762 * 2763 * 1. The destination register cannot overlap the source register. 2764 * 2. If masked, cannot overlap the mask register ('v0'). 2765 * 3. An illegal instruction exception is raised if vstart is non-zero. 2766 */ 2767static bool trans_viota_m(DisasContext *s, arg_viota_m *a) 2768{ 2769 if (require_rvv(s) && 2770 vext_check_isa_ill(s) && 2771 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs2, 1) && 2772 require_vm(a->vm, a->rd) && 2773 require_align(a->rd, s->lmul)) { 2774 uint32_t data = 0; 2775 TCGLabel *over = gen_new_label(); 2776 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2777 2778 data = FIELD_DP32(data, VDATA, VM, a->vm); 2779 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2780 static gen_helper_gvec_3_ptr * const fns[4] = { 2781 gen_helper_viota_m_b, gen_helper_viota_m_h, 2782 gen_helper_viota_m_w, gen_helper_viota_m_d, 2783 }; 2784 tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2785 vreg_ofs(s, a->rs2), cpu_env, 2786 s->vlen / 8, s->vlen / 8, data, fns[s->sew]); 2787 mark_vs_dirty(s); 2788 gen_set_label(over); 2789 return true; 2790 } 2791 return false; 2792} 2793 2794/* Vector Element Index Instruction */ 2795static bool trans_vid_v(DisasContext *s, arg_vid_v *a) 2796{ 2797 if (require_rvv(s) && 2798 vext_check_isa_ill(s) && 2799 require_align(a->rd, s->lmul) && 2800 require_vm(a->vm, a->rd)) { 2801 uint32_t data = 0; 2802 TCGLabel *over = gen_new_label(); 2803 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2804 2805 data = FIELD_DP32(data, VDATA, VM, a->vm); 2806 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 2807 static gen_helper_gvec_2_ptr * const fns[4] = { 2808 gen_helper_vid_v_b, gen_helper_vid_v_h, 2809 gen_helper_vid_v_w, gen_helper_vid_v_d, 2810 }; 2811 tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 2812 cpu_env, s->vlen / 8, s->vlen / 8, 2813 data, fns[s->sew]); 2814 mark_vs_dirty(s); 2815 gen_set_label(over); 2816 return true; 2817 } 2818 return false; 2819} 2820 2821/* 2822 *** Vector Permutation Instructions 2823 */ 2824 2825/* Integer Extract Instruction */ 2826 2827static void load_element(TCGv_i64 dest, TCGv_ptr base, 2828 int ofs, int sew) 2829{ 2830 switch (sew) { 2831 case MO_8: 2832 tcg_gen_ld8u_i64(dest, base, ofs); 2833 break; 2834 case MO_16: 2835 tcg_gen_ld16u_i64(dest, base, ofs); 2836 break; 2837 case MO_32: 2838 tcg_gen_ld32u_i64(dest, base, ofs); 2839 break; 2840 case MO_64: 2841 tcg_gen_ld_i64(dest, base, ofs); 2842 break; 2843 default: 2844 g_assert_not_reached(); 2845 break; 2846 } 2847} 2848 2849/* offset of the idx element with base regsiter r */ 2850static uint32_t endian_ofs(DisasContext *s, int r, int idx) 2851{ 2852#ifdef HOST_WORDS_BIGENDIAN 2853 return vreg_ofs(s, r) + ((idx ^ (7 >> s->sew)) << s->sew); 2854#else 2855 return vreg_ofs(s, r) + (idx << s->sew); 2856#endif 2857} 2858 2859/* adjust the index according to the endian */ 2860static void endian_adjust(TCGv_i32 ofs, int sew) 2861{ 2862#ifdef HOST_WORDS_BIGENDIAN 2863 tcg_gen_xori_i32(ofs, ofs, 7 >> sew); 2864#endif 2865} 2866 2867/* Load idx >= VLMAX ? 0 : vreg[idx] */ 2868static void vec_element_loadx(DisasContext *s, TCGv_i64 dest, 2869 int vreg, TCGv idx, int vlmax) 2870{ 2871 TCGv_i32 ofs = tcg_temp_new_i32(); 2872 TCGv_ptr base = tcg_temp_new_ptr(); 2873 TCGv_i64 t_idx = tcg_temp_new_i64(); 2874 TCGv_i64 t_vlmax, t_zero; 2875 2876 /* 2877 * Mask the index to the length so that we do 2878 * not produce an out-of-range load. 2879 */ 2880 tcg_gen_trunc_tl_i32(ofs, idx); 2881 tcg_gen_andi_i32(ofs, ofs, vlmax - 1); 2882 2883 /* Convert the index to an offset. */ 2884 endian_adjust(ofs, s->sew); 2885 tcg_gen_shli_i32(ofs, ofs, s->sew); 2886 2887 /* Convert the index to a pointer. */ 2888 tcg_gen_ext_i32_ptr(base, ofs); 2889 tcg_gen_add_ptr(base, base, cpu_env); 2890 2891 /* Perform the load. */ 2892 load_element(dest, base, 2893 vreg_ofs(s, vreg), s->sew); 2894 tcg_temp_free_ptr(base); 2895 tcg_temp_free_i32(ofs); 2896 2897 /* Flush out-of-range indexing to zero. */ 2898 t_vlmax = tcg_constant_i64(vlmax); 2899 t_zero = tcg_constant_i64(0); 2900 tcg_gen_extu_tl_i64(t_idx, idx); 2901 2902 tcg_gen_movcond_i64(TCG_COND_LTU, dest, t_idx, 2903 t_vlmax, dest, t_zero); 2904 2905 tcg_temp_free_i64(t_idx); 2906} 2907 2908static void vec_element_loadi(DisasContext *s, TCGv_i64 dest, 2909 int vreg, int idx) 2910{ 2911 load_element(dest, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2912} 2913 2914static bool trans_vext_x_v(DisasContext *s, arg_r *a) 2915{ 2916 TCGv_i64 tmp = tcg_temp_new_i64(); 2917 TCGv dest = dest_gpr(s, a->rd); 2918 2919 if (a->rs1 == 0) { 2920 /* Special case vmv.x.s rd, vs2. */ 2921 vec_element_loadi(s, tmp, a->rs2, 0); 2922 } else { 2923 /* This instruction ignores LMUL and vector register groups */ 2924 int vlmax = s->vlen >> (3 + s->sew); 2925 vec_element_loadx(s, tmp, a->rs2, cpu_gpr[a->rs1], vlmax); 2926 } 2927 2928 tcg_gen_trunc_i64_tl(dest, tmp); 2929 gen_set_gpr(s, a->rd, dest); 2930 2931 tcg_temp_free_i64(tmp); 2932 return true; 2933} 2934 2935/* Integer Scalar Move Instruction */ 2936 2937static void store_element(TCGv_i64 val, TCGv_ptr base, 2938 int ofs, int sew) 2939{ 2940 switch (sew) { 2941 case MO_8: 2942 tcg_gen_st8_i64(val, base, ofs); 2943 break; 2944 case MO_16: 2945 tcg_gen_st16_i64(val, base, ofs); 2946 break; 2947 case MO_32: 2948 tcg_gen_st32_i64(val, base, ofs); 2949 break; 2950 case MO_64: 2951 tcg_gen_st_i64(val, base, ofs); 2952 break; 2953 default: 2954 g_assert_not_reached(); 2955 break; 2956 } 2957} 2958 2959/* 2960 * Store vreg[idx] = val. 2961 * The index must be in range of VLMAX. 2962 */ 2963static void vec_element_storei(DisasContext *s, int vreg, 2964 int idx, TCGv_i64 val) 2965{ 2966 store_element(val, cpu_env, endian_ofs(s, vreg, idx), s->sew); 2967} 2968 2969/* vmv.s.x vd, rs1 # vd[0] = rs1 */ 2970static bool trans_vmv_s_x(DisasContext *s, arg_vmv_s_x *a) 2971{ 2972 if (vext_check_isa_ill(s)) { 2973 /* This instruction ignores LMUL and vector register groups */ 2974 int maxsz = s->vlen >> 3; 2975 TCGv_i64 t1; 2976 TCGLabel *over = gen_new_label(); 2977 2978 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 2979 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), maxsz, maxsz, 0); 2980 if (a->rs1 == 0) { 2981 goto done; 2982 } 2983 2984 t1 = tcg_temp_new_i64(); 2985 tcg_gen_extu_tl_i64(t1, cpu_gpr[a->rs1]); 2986 vec_element_storei(s, a->rd, 0, t1); 2987 tcg_temp_free_i64(t1); 2988 mark_vs_dirty(s); 2989 done: 2990 gen_set_label(over); 2991 return true; 2992 } 2993 return false; 2994} 2995 2996/* Floating-Point Scalar Move Instructions */ 2997static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) 2998{ 2999 if (!s->vill && has_ext(s, RVF) && 3000 (s->mstatus_fs != 0) && (s->sew != 0)) { 3001 unsigned int len = 8 << s->sew; 3002 3003 vec_element_loadi(s, cpu_fpr[a->rd], a->rs2, 0); 3004 if (len < 64) { 3005 tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 3006 MAKE_64BIT_MASK(len, 64 - len)); 3007 } 3008 3009 mark_fs_dirty(s); 3010 return true; 3011 } 3012 return false; 3013} 3014 3015/* vfmv.s.f vd, rs1 # vd[0] = rs1 (vs2=0) */ 3016static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) 3017{ 3018 if (!s->vill && has_ext(s, RVF) && (s->sew != 0)) { 3019 TCGv_i64 t1; 3020 /* The instructions ignore LMUL and vector register group. */ 3021 uint32_t vlmax = s->vlen >> 3; 3022 3023 /* if vl == 0, skip vector register write back */ 3024 TCGLabel *over = gen_new_label(); 3025 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3026 3027 /* zeroed all elements */ 3028 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), vlmax, vlmax, 0); 3029 3030 /* NaN-box f[rs1] as necessary for SEW */ 3031 t1 = tcg_temp_new_i64(); 3032 if (s->sew == MO_64 && !has_ext(s, RVD)) { 3033 tcg_gen_ori_i64(t1, cpu_fpr[a->rs1], MAKE_64BIT_MASK(32, 32)); 3034 } else { 3035 tcg_gen_mov_i64(t1, cpu_fpr[a->rs1]); 3036 } 3037 vec_element_storei(s, a->rd, 0, t1); 3038 tcg_temp_free_i64(t1); 3039 mark_vs_dirty(s); 3040 gen_set_label(over); 3041 return true; 3042 } 3043 return false; 3044} 3045 3046/* Vector Slide Instructions */ 3047static bool slideup_check(DisasContext *s, arg_rmrr *a) 3048{ 3049 return require_rvv(s) && 3050 vext_check_isa_ill(s) && 3051 vext_check_slide(s, a->rd, a->rs2, a->vm, true); 3052} 3053 3054GEN_OPIVX_TRANS(vslideup_vx, slideup_check) 3055GEN_OPIVX_TRANS(vslide1up_vx, slideup_check) 3056GEN_OPIVI_TRANS(vslideup_vi, IMM_ZX, vslideup_vx, slideup_check) 3057 3058static bool slidedown_check(DisasContext *s, arg_rmrr *a) 3059{ 3060 return require_rvv(s) && 3061 vext_check_isa_ill(s) && 3062 vext_check_slide(s, a->rd, a->rs2, a->vm, false); 3063} 3064 3065GEN_OPIVX_TRANS(vslidedown_vx, slidedown_check) 3066GEN_OPIVX_TRANS(vslide1down_vx, slidedown_check) 3067GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) 3068 3069/* Vector Register Gather Instruction */ 3070static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) 3071{ 3072 return require_rvv(s) && 3073 vext_check_isa_ill(s) && 3074 require_align(a->rd, s->lmul) && 3075 require_align(a->rs1, s->lmul) && 3076 require_align(a->rs2, s->lmul) && 3077 (a->rd != a->rs2 && a->rd != a->rs1) && 3078 require_vm(a->vm, a->rd); 3079} 3080 3081GEN_OPIVV_TRANS(vrgather_vv, vrgather_vv_check) 3082 3083static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) 3084{ 3085 return require_rvv(s) && 3086 vext_check_isa_ill(s) && 3087 require_align(a->rd, s->lmul) && 3088 require_align(a->rs2, s->lmul) && 3089 (a->rd != a->rs2) && 3090 require_vm(a->vm, a->rd); 3091} 3092 3093/* vrgather.vx vd, vs2, rs1, vm # vd[i] = (x[rs1] >= VLMAX) ? 0 : vs2[rs1] */ 3094static bool trans_vrgather_vx(DisasContext *s, arg_rmrr *a) 3095{ 3096 if (!vrgather_vx_check(s, a)) { 3097 return false; 3098 } 3099 3100 if (a->vm && s->vl_eq_vlmax) { 3101 int vlmax = s->vlen; 3102 TCGv_i64 dest = tcg_temp_new_i64(); 3103 3104 if (a->rs1 == 0) { 3105 vec_element_loadi(s, dest, a->rs2, 0); 3106 } else { 3107 vec_element_loadx(s, dest, a->rs2, cpu_gpr[a->rs1], vlmax); 3108 } 3109 3110 tcg_gen_gvec_dup_i64(s->sew, vreg_ofs(s, a->rd), 3111 MAXSZ(s), MAXSZ(s), dest); 3112 tcg_temp_free_i64(dest); 3113 mark_vs_dirty(s); 3114 } else { 3115 static gen_helper_opivx * const fns[4] = { 3116 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3117 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3118 }; 3119 return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s); 3120 } 3121 return true; 3122} 3123 3124/* vrgather.vi vd, vs2, imm, vm # vd[i] = (imm >= VLMAX) ? 0 : vs2[imm] */ 3125static bool trans_vrgather_vi(DisasContext *s, arg_rmrr *a) 3126{ 3127 if (!vrgather_vx_check(s, a)) { 3128 return false; 3129 } 3130 3131 if (a->vm && s->vl_eq_vlmax) { 3132 if (a->rs1 >= s->vlen) { 3133 tcg_gen_gvec_dup_imm(SEW64, vreg_ofs(s, a->rd), 3134 MAXSZ(s), MAXSZ(s), 0); 3135 } else { 3136 tcg_gen_gvec_dup_mem(s->sew, vreg_ofs(s, a->rd), 3137 endian_ofs(s, a->rs2, a->rs1), 3138 MAXSZ(s), MAXSZ(s)); 3139 } 3140 mark_vs_dirty(s); 3141 } else { 3142 static gen_helper_opivx * const fns[4] = { 3143 gen_helper_vrgather_vx_b, gen_helper_vrgather_vx_h, 3144 gen_helper_vrgather_vx_w, gen_helper_vrgather_vx_d 3145 }; 3146 return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], 3147 s, IMM_ZX); 3148 } 3149 return true; 3150} 3151 3152/* 3153 * Vector Compress Instruction 3154 * 3155 * The destination vector register group cannot overlap the 3156 * source vector register group or the source mask register. 3157 */ 3158static bool vcompress_vm_check(DisasContext *s, arg_r *a) 3159{ 3160 return require_rvv(s) && 3161 vext_check_isa_ill(s) && 3162 require_align(a->rd, s->lmul) && 3163 require_align(a->rs2, s->lmul) && 3164 (a->rd != a->rs2) && 3165 !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1); 3166} 3167 3168static bool trans_vcompress_vm(DisasContext *s, arg_r *a) 3169{ 3170 if (vcompress_vm_check(s, a)) { 3171 uint32_t data = 0; 3172 static gen_helper_gvec_4_ptr * const fns[4] = { 3173 gen_helper_vcompress_vm_b, gen_helper_vcompress_vm_h, 3174 gen_helper_vcompress_vm_w, gen_helper_vcompress_vm_d, 3175 }; 3176 TCGLabel *over = gen_new_label(); 3177 tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); 3178 3179 data = FIELD_DP32(data, VDATA, LMUL, s->lmul); 3180 tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), 3181 vreg_ofs(s, a->rs1), vreg_ofs(s, a->rs2), 3182 cpu_env, s->vlen / 8, s->vlen / 8, data, 3183 fns[s->sew]); 3184 mark_vs_dirty(s); 3185 gen_set_label(over); 3186 return true; 3187 } 3188 return false; 3189} 3190