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