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