From nobody Sat Sep 6 14:37:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1756907852522939.5479904560394; Wed, 3 Sep 2025 06:57:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1utnyb-00079y-3i; Wed, 03 Sep 2025 09:56:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1utnyU-00077R-MM; Wed, 03 Sep 2025 09:56:34 -0400 Received: from [115.124.28.61] (helo=out28-61.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1utnyN-0002Mr-K9; Wed, 03 Sep 2025 09:56:34 -0400 Received: from ZEVORN-PC(mailfrom:chao.liu@zevorn.cn fp:SMTPD_---.eWfK6Si_1756907528 cluster:ay29) by smtp.aliyun-inc.com; Wed, 03 Sep 2025 21:52:08 +0800 From: Chao Liu To: richard.henderson@linaro.org, paolo.savini@embecosm.com, npiggin@gmail.com, ebiggers@kernel.org, dbarboza@ventanamicro.com, palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com Cc: qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Chao Liu , Chao Liu Subject: [PATCH v6 1/2] target/riscv: Generate strided vector loads/stores with tcg nodes. Date: Wed, 3 Sep 2025 21:52:01 +0800 Message-ID: X-Mailer: git-send-email 2.50.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.28.61 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=115.124.28.61; envelope-from=chao.liu@zevorn.cn; helo=out28-61.mail.aliyun.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1756907855222124100 Content-Type: text/plain; charset="utf-8" From: Chao Liu This commit improves the performance of QEMU when emulating strided vector loads and stores by substituting the call for the helper function with the generation of equivalent TCG operations. PS: An implementation is permitted to cause an illegal instruction if vstart is not 0 and it is set to a value that can not be produced implicitly by the implementation, but memory accesses will generally always need to deal with page faults. So, if a strided vector memory access instruction has non-zero vstart, check it through vlse/vsse helpers function. Signed-off-by: Paolo Savini Signed-off-by: Chao Liu Signed-off-by: Nicholas Piggin Tested-by: Eric Biggers Reviewed-by: Daniel Henrique Barboza --- target/riscv/insn_trans/trans_rvv.c.inc | 321 +++++++++++++++++++++--- 1 file changed, 283 insertions(+), 38 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_tr= ans/trans_rvv.c.inc index 71f98fb350..1980476c83 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -864,32 +864,298 @@ GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld= _us_mask_check) GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check) =20 /* - *** stride load and store + * MAXSZ returns the maximum vector size can be operated in bytes, + * which is used in GVEC IR when vl_eq_vlmax flag is set to true + * to accelerate vector operation. */ +static inline uint32_t MAXSZ(DisasContext *s) +{ + int max_sz =3D s->cfg_ptr->vlenb << 3; + return max_sz >> (3 - s->lmul); +} + +static inline uint32_t get_log2(uint32_t a) +{ + assert(is_power_of_2(a)); + return ctz32(a); +} + +typedef void gen_tl_ldst(TCGv, TCGv_ptr, tcg_target_long); + +/* + * Simulate the strided load/store main loop: + * + * for (i =3D env->vstart; i < env->vl; env->vstart =3D ++i) { + * k =3D 0; + * while (k < nf) { + * if (!vm && !vext_elem_mask(v0, i)) { + * vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + * (i + k * max_elems + 1) * esz); + * k++; + * continue; + * } + * target_ulong addr =3D base + stride * i + (k << log2_esz); + * ldst(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); + * k++; + * } + * } + */ +static void gen_ldst_stride_main_loop(DisasContext *s, TCGv dest, uint32_t= rs1, + uint32_t rs2, uint32_t vm, uint32_t = nf, + gen_tl_ldst *ld_fn, gen_tl_ldst *st_= fn, + bool is_load) +{ + TCGv addr =3D tcg_temp_new(); + TCGv base =3D get_gpr(s, rs1, EXT_NONE); + TCGv stride =3D get_gpr(s, rs2, EXT_NONE); + + TCGv i =3D tcg_temp_new(); + TCGv i_esz =3D tcg_temp_new(); + TCGv k =3D tcg_temp_new(); + TCGv k_esz =3D tcg_temp_new(); + TCGv k_max =3D tcg_temp_new(); + TCGv mask =3D tcg_temp_new(); + TCGv mask_offs =3D tcg_temp_new(); + TCGv mask_offs_64 =3D tcg_temp_new(); + TCGv mask_elem =3D tcg_temp_new(); + TCGv mask_offs_rem =3D tcg_temp_new(); + TCGv vreg =3D tcg_temp_new(); + TCGv dest_offs =3D tcg_temp_new(); + TCGv stride_offs =3D tcg_temp_new(); + + uint32_t max_elems =3D MAXSZ(s) >> s->sew; + + TCGLabel *start =3D gen_new_label(); + TCGLabel *end =3D gen_new_label(); + TCGLabel *start_k =3D gen_new_label(); + TCGLabel *inc_k =3D gen_new_label(); + TCGLabel *end_k =3D gen_new_label(); + + MemOp atomicity =3D MO_ATOM_NONE; + if (s->sew =3D=3D 0) { + atomicity =3D MO_ATOM_NONE; + } else { + atomicity =3D MO_ATOM_IFALIGN_PAIR; + } + + tcg_gen_addi_tl(mask, (TCGv)tcg_env, vreg_ofs(s, 0)); + + /* Start of outer loop. */ + tcg_gen_mov_tl(i, cpu_vstart); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, i, cpu_vl, end); + tcg_gen_shli_tl(i_esz, i, s->sew); + /* Start of inner loop. */ + tcg_gen_movi_tl(k, 0); + gen_set_label(start_k); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end_k); + /* + * If we are in mask agnostic regime and the operation is not unmasked= we + * set the inactive elements to 1. + */ + if (!vm && s->vma) { + TCGLabel *active_element =3D gen_new_label(); + /* (i + k * max_elems) * esz */ + tcg_gen_shli_tl(mask_offs, k, get_log2(max_elems << s->sew)); + tcg_gen_add_tl(mask_offs, mask_offs, i_esz); + + /* + * Check whether the i bit of the mask is 0 or 1. + * + * static inline int vext_elem_mask(void *v0, int index) + * { + * int idx =3D index / 64; + * int pos =3D index % 64; + * return (((uint64_t *)v0)[idx] >> pos) & 1; + * } + */ + tcg_gen_shri_tl(mask_offs_64, mask_offs, 3); + tcg_gen_add_tl(mask_offs_64, mask_offs_64, mask); + tcg_gen_ld_i64((TCGv_i64)mask_elem, (TCGv_ptr)mask_offs_64, 0); + tcg_gen_rem_tl(mask_offs_rem, mask_offs, tcg_constant_tl(8)); + tcg_gen_shr_tl(mask_elem, mask_elem, mask_offs_rem); + tcg_gen_andi_tl(mask_elem, mask_elem, 1); + tcg_gen_brcond_tl(TCG_COND_NE, mask_elem, tcg_constant_tl(0), + active_element); + /* + * Set masked-off elements in the destination vector register to 1= s. + * Store instructions simply skip this bit as memory ops access me= mory + * only for active elements. + */ + if (is_load) { + tcg_gen_shli_tl(mask_offs, mask_offs, s->sew); + tcg_gen_add_tl(mask_offs, mask_offs, dest); + st_fn(tcg_constant_tl(-1), (TCGv_ptr)mask_offs, 0); + } + tcg_gen_br(inc_k); + gen_set_label(active_element); + } + /* + * The element is active, calculate the address with stride: + * target_ulong addr =3D base + stride * i + (k << log2_esz); + */ + tcg_gen_mul_tl(stride_offs, stride, i); + tcg_gen_shli_tl(k_esz, k, s->sew); + tcg_gen_add_tl(stride_offs, stride_offs, k_esz); + tcg_gen_add_tl(addr, base, stride_offs); + /* Calculate the offset in the dst/src vector register. */ + tcg_gen_shli_tl(k_max, k, get_log2(max_elems)); + tcg_gen_add_tl(dest_offs, i, k_max); + tcg_gen_shli_tl(dest_offs, dest_offs, s->sew); + tcg_gen_add_tl(dest_offs, dest_offs, dest); + if (is_load) { + tcg_gen_qemu_ld_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomic= ity); + st_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + } else { + ld_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + tcg_gen_qemu_st_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomic= ity); + } + /* + * We don't execute the load/store above if the element was inactive. + * We jump instead directly to incrementing k and continuing the loop. + */ + if (!vm && s->vma) { + gen_set_label(inc_k); + } + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start_k); + /* End of the inner loop. */ + gen_set_label(end_k); + + tcg_gen_addi_tl(i, i, 1); + tcg_gen_mov_tl(cpu_vstart, i); + tcg_gen_br(start); + + /* End of the outer loop. */ + gen_set_label(end); + + return; +} + +/* + * Set the tail bytes of the strided loads/stores to 1: + * + * for (k =3D 0; k < nf; ++k) { + * cnt =3D (k * max_elems + vl) * esz; + * tot =3D (k * max_elems + max_elems) * esz; + * for (i =3D cnt; i < tot; i +=3D esz) { + * store_1s(-1, vd[vl+i]); + * } + * } + */ +static void gen_ldst_stride_tail_loop(DisasContext *s, TCGv dest, uint32_t= nf, + gen_tl_ldst *st_fn) +{ + TCGv i =3D tcg_temp_new(); + TCGv k =3D tcg_temp_new(); + TCGv tail_cnt =3D tcg_temp_new(); + TCGv tail_tot =3D tcg_temp_new(); + TCGv tail_addr =3D tcg_temp_new(); + + TCGLabel *start =3D gen_new_label(); + TCGLabel *end =3D gen_new_label(); + TCGLabel *start_i =3D gen_new_label(); + TCGLabel *end_i =3D gen_new_label(); + + uint32_t max_elems_b =3D MAXSZ(s); + uint32_t esz =3D 1 << s->sew; + + /* Start of the outer loop. */ + tcg_gen_movi_tl(k, 0); + tcg_gen_shli_tl(tail_cnt, cpu_vl, s->sew); + tcg_gen_movi_tl(tail_tot, max_elems_b); + tcg_gen_add_tl(tail_addr, dest, tail_cnt); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end); + /* Start of the inner loop. */ + tcg_gen_mov_tl(i, tail_cnt); + gen_set_label(start_i); + tcg_gen_brcond_tl(TCG_COND_GE, i, tail_tot, end_i); + /* store_1s(-1, vd[vl+i]); */ + st_fn(tcg_constant_tl(-1), (TCGv_ptr)tail_addr, 0); + tcg_gen_addi_tl(tail_addr, tail_addr, esz); + tcg_gen_addi_tl(i, i, esz); + tcg_gen_br(start_i); + /* End of the inner loop. */ + gen_set_label(end_i); + /* Update the counts */ + tcg_gen_addi_tl(tail_cnt, tail_cnt, max_elems_b); + tcg_gen_addi_tl(tail_tot, tail_cnt, max_elems_b); + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start); + /* End of the outer loop. */ + gen_set_label(end); + + return; +} + typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, TCGv, TCGv_env, TCGv_i32); =20 static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, uint32_t data, gen_helper_ldst_stride *fn, - DisasContext *s) + DisasContext *s, bool is_load) { - TCGv_ptr dest, mask; - TCGv base, stride; - TCGv_i32 desc; + if (!s->vstart_eq_zero) { + TCGv_ptr dest, mask; + TCGv base, stride; + TCGv_i32 desc; =20 - dest =3D tcg_temp_new_ptr(); - mask =3D tcg_temp_new_ptr(); - base =3D get_gpr(s, rs1, EXT_NONE); - stride =3D get_gpr(s, rs2, EXT_NONE); - desc =3D tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, - s->cfg_ptr->vlenb, data)); + dest =3D tcg_temp_new_ptr(); + mask =3D tcg_temp_new_ptr(); + base =3D get_gpr(s, rs1, EXT_NONE); + stride =3D get_gpr(s, rs2, EXT_NONE); + desc =3D tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); =20 - tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); + mark_vs_dirty(s); + fn(dest, mask, base, stride, tcg_env, desc); + return true; + } + + TCGv dest =3D tcg_temp_new(); + + uint32_t nf =3D FIELD_EX32(data, VDATA, NF); + uint32_t vm =3D FIELD_EX32(data, VDATA, VM); + + /* Destination register and mask register */ + tcg_gen_addi_tl(dest, (TCGv)tcg_env, vreg_ofs(s, vd)); + + /* + * Select the appropriate load/tore to retrieve data from the vector + * register given a specific sew. + */ + static gen_tl_ldst * const ld_fns[4] =3D { + tcg_gen_ld8u_tl, tcg_gen_ld16u_tl, + tcg_gen_ld32u_tl, tcg_gen_ld_tl + }; + + static gen_tl_ldst * const st_fns[4] =3D { + tcg_gen_st8_tl, tcg_gen_st16_tl, + tcg_gen_st32_tl, tcg_gen_st_tl + }; + + gen_tl_ldst *ld_fn =3D ld_fns[s->sew]; + gen_tl_ldst *st_fn =3D st_fns[s->sew]; + + if (ld_fn =3D=3D NULL || st_fn =3D=3D NULL) { + return false; + } =20 mark_vs_dirty(s); =20 - fn(dest, mask, base, stride, tcg_env, desc); + gen_ldst_stride_main_loop(s, dest, rs1, rs2, vm, nf, ld_fn, st_fn, is_= load); + + tcg_gen_movi_tl(cpu_vstart, 0); + + /* + * Set the tail bytes to 1 if tail agnostic: + */ + if (s->vta !=3D 0 && is_load) { + gen_ldst_stride_tail_loop(s, dest, nf, st_fn); + } =20 finalize_rvv_inst(s); return true; @@ -899,7 +1165,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a= , uint8_t eew) { uint32_t data =3D 0; gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] =3D { + static gen_helper_ldst_stride *const fns[4] =3D { gen_helper_vlse8_v, gen_helper_vlse16_v, gen_helper_vlse32_v, gen_helper_vlse64_v }; @@ -915,7 +1181,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a= , uint8_t eew) data =3D FIELD_DP32(data, VDATA, NF, a->nf); data =3D FIELD_DP32(data, VDATA, VTA, s->vta); data =3D FIELD_DP32(data, VDATA, VMA, s->vma); - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s, true); } =20 static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -933,23 +1199,13 @@ GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op,= ld_stride_check) static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) { uint32_t data =3D 0; - gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] =3D { - /* masked stride store */ - gen_helper_vsse8_v, gen_helper_vsse16_v, - gen_helper_vsse32_v, gen_helper_vsse64_v - }; =20 uint8_t emul =3D vext_get_emul(s, eew); data =3D FIELD_DP32(data, VDATA, VM, a->vm); data =3D FIELD_DP32(data, VDATA, LMUL, emul); data =3D FIELD_DP32(data, VDATA, NF, a->nf); - fn =3D fns[eew]; - if (fn =3D=3D NULL) { - return false; - } =20 - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, NULL, s, false); } =20 static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -1300,17 +1556,6 @@ GEN_LDST_WHOLE_TRANS(vs8r_v, int8_t, 8, false) *** Vector Integer Arithmetic Instructions */ =20 -/* - * MAXSZ returns the maximum vector size can be operated in bytes, - * which is used in GVEC IR when vl_eq_vlmax flag is set to true - * to accelerate vector operation. - */ -static inline uint32_t MAXSZ(DisasContext *s) -{ - int max_sz =3D s->cfg_ptr->vlenb * 8; - return max_sz >> (3 - s->lmul); -} - static bool opivv_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && --=20 2.50.1 From nobody Sat Sep 6 14:37:10 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1756907832163821.3792606294896; Wed, 3 Sep 2025 06:57:12 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1utnyU-00076v-Fi; Wed, 03 Sep 2025 09:56:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1utnyS-00075r-5k; Wed, 03 Sep 2025 09:56:32 -0400 Received: from [115.124.28.38] (helo=out28-38.mail.aliyun.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1utnyN-0002Mu-KT; Wed, 03 Sep 2025 09:56:31 -0400 Received: from ZEVORN-PC(mailfrom:chao.liu@zevorn.cn fp:SMTPD_---.eWfK6TQ_1756907529 cluster:ay29) by smtp.aliyun-inc.com; Wed, 03 Sep 2025 21:52:09 +0800 From: Chao Liu To: richard.henderson@linaro.org, paolo.savini@embecosm.com, npiggin@gmail.com, ebiggers@kernel.org, dbarboza@ventanamicro.com, palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com Cc: qemu-riscv@nongnu.org, qemu-devel@nongnu.org, Chao Liu , Chao Liu Subject: [PATCH v6 2/2] tests/tcg/riscv64: Add test for vlsseg8e32 instruction Date: Wed, 3 Sep 2025 21:52:02 +0800 Message-ID: <4e4c7f7cef0fe267c58b1191599e3ed33830721a.1756906528.git.chao.liu@zevorn.cn> X-Mailer: git-send-email 2.50.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 115.124.28.38 (deferred) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=115.124.28.38; envelope-from=chao.liu@zevorn.cn; helo=out28-38.mail.aliyun.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1756907835832124100 Content-Type: text/plain; charset="utf-8" From: Chao Liu This case, it copied 64 bytes from a0 to a1 with vlsseg8e32. Signed-off-by: Chao Liu Signed-off-by: Nicholas Piggin --- tests/tcg/riscv64/Makefile.softmmu-target | 7 +- tests/tcg/riscv64/test-vlsseg8e32.S | 107 ++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/riscv64/test-vlsseg8e32.S diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/= Makefile.softmmu-target index 3ca595335d..e52c005f87 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -7,7 +7,7 @@ VPATH +=3D $(TEST_SRC) =20 LINK_SCRIPT =3D $(TEST_SRC)/semihost.ld LDFLAGS =3D -T $(LINK_SCRIPT) -CFLAGS +=3D -g -Og +CFLAGS +=3D -march=3Drv64gcv -mabi=3Dlp64d -g -Og =20 %.o: %.S $(CC) $(CFLAGS) $< -Wa,--noexecstack -c -o $@ @@ -24,5 +24,10 @@ EXTRA_RUNS +=3D run-test-mepc-masking run-test-mepc-masking: test-mepc-masking $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) =20 +EXTRA_RUNS +=3D run-vlsseg8e32 +run-vlsseg8e32: QEMU_OPTS :=3D -cpu rv64,v=3Dtrue $(QEMU_OPTS) +run-vlsseg8e32: test-vlsseg8e32 + $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) + # We don't currently support the multiarch system tests undefine MULTIARCH_TESTS diff --git a/tests/tcg/riscv64/test-vlsseg8e32.S b/tests/tcg/riscv64/test-v= lsseg8e32.S new file mode 100644 index 0000000000..bbc79d5e8d --- /dev/null +++ b/tests/tcg/riscv64/test-vlsseg8e32.S @@ -0,0 +1,107 @@ +# +# QEMU RISC-V Vector Strided Load Instruction testcase +# +# Copyright (c) 2025 Chao Liu chao.liu@yeah.net +# +# SPDX-License-Identifier: GPL-2.0-or-later +# + .option norvc + + .section .data + .align 4 +source_data: + .asciz "Test the vssseg8e32 insn by copy 64b and verifying correctness." + .equ source_len, 64 + + .text + .global _start +_start: + lla t0, trap + csrw mtvec, t0 + +enable_rvv: + + li x15, 0x800000000024112d + csrw 0x301, x15 + li x1, 0x2200 + csrr x2, mstatus + or x2, x2, x1 + csrw mstatus, x2 + +rvv_test_func: + la a0, source_data + li a1, 0x80020000 + vsetivli zero, 1, e32, m1, ta, ma + li t0, 64 + + vlsseg8e32.v v0, (a0), t0 + addi a0, a0, 32 + vlsseg8e32.v v8, (a0), t0 + + vssseg8e32.v v0, (a1), t0 + addi a1, a1, 32 + vssseg8e32.v v8, (a1), t0 + +compare_start: + la a0, source_data + li a1, 0x80020000 + li t0, 0 + li t1, source_len + +compare_loop: + # when t0 >=3D len, compare end + bge t0, t1, compare_done + + lb t2, 0(a0) + lb t3, 0(a1) + bne t2, t3, compare_fail + + addi a0, a0, 1 + addi a1, a1, 1 + addi t0, t0, 1 + j compare_loop + +compare_done: + # compare ok, return 0 + li a0, 0 + j _exit + +compare_fail: + # compare failed, return 2 + li a0, 2 + j _exit + +trap: + # When an instruction traps, compare it to the insn in memory. + csrr t0, mepc + csrr t1, mtval + lwu t2, 0(t0) + bne t1, t2, fail + + # Skip the insn and continue. + addi t0, t0, 4 + csrw mepc, t0 + mret + +fail: + li a0, 1 + +# Exit code in a0 +_exit: + lla a1, semiargs + li t0, 0x20026 # ADP_Stopped_ApplicationExit + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED + + # Semihosting call sequence + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 --=20 2.50.1