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