vsetvli and vsetivli currently call the generic vsetvl helper even
when their immediate vtype can be validated during translation. For
legal RV64 LMUL=1 configurations, generate the VL calculation and
architectural state updates directly in TCG to avoid the runtime
helper call and repeated validation of the constant type.
Restrict this path to encodings without reserved or alternate-format
bits and with an element width supported by the configured ELEN.
Compute VL during translation for vsetivli, where AVL is also an
immediate. For vsetvli with a nonzero source register, generate an
unsigned minimum and, when required, conditional selection for the
rvv_vl_half_avl policy. Preserve the rounded-up half-AVL result for
VLMAX < AVL < 2 * VLMAX.
Write vl and vtype, clear vstart and VILL, and return the selected VL
through the destination register. Compute the result before writing
the destination so that rd may alias the AVL source register. Use
the existing 32-bit TCG globals for vl and vstart.
Keep the generic helper for RV32, other LMUL values, unsupported
types, register-supplied vtype, and vsetvli with rs1=x0. In particular,
retain the existing handling of the x0 forms and their VILL policy.
Leave instruction checks, finalization, PC updates and the subsequent
translation-block lookup unchanged.
The preceding regression test covers AVL boundaries, register aliases,
state updates, helper fallback cases and subsequent vector arithmetic
with both VL selection policies.
---
target/riscv/tcg/insn_trans/trans_rvv.c.inc | 79 +++++++++++++++++++--
1 file changed, 72 insertions(+), 7 deletions(-)
diff --git a/target/riscv/tcg/insn_trans/trans_rvv.c.inc
b/target/riscv/tcg/insn_trans/trans_rvv.c.inc
index 7e1295f33e..d26844c99c 100644
--- a/target/riscv/tcg/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/tcg/insn_trans/trans_rvv.c.inc
@@ -221,7 +221,26 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1,
TCGv s2)
return true;
}
-static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2)
+static bool vsetvl_inline_vtype(DisasContext *s, unsigned vtype)
+{
+ unsigned vsew = FIELD_EX64(vtype, VTYPE, VSEW);
+
+ /* RV64, LMUL=1, no reserved or alternate-format bits. */
+ return get_xl(s) == MXL_RV64 && !(vtype & ~0xf8u) &&
+ (8u << vsew) <= s->cfg_ptr->elen;
+}
+
+static void gen_vsetvl_inline_state(TCGv vl, unsigned vtype)
+{
+ tcg_gen_trunc_tl_i32(cpu_vl, vl);
+ tcg_gen_st_tl(tcg_constant_tl(vtype), tcg_env,
+ offsetof(CPURISCVState, vtype));
+ tcg_gen_movi_i32(cpu_vstart, 0);
+ tcg_gen_st8_i32(tcg_constant_i32(0), tcg_env,
+ offsetof(CPURISCVState, vill));
+}
+
+static bool do_vsetivli(DisasContext *s, int rd, unsigned avl, unsigned vtype)
{
TCGv dst;
@@ -231,7 +250,20 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1,
TCGv s2)
dst = dest_gpr(s, rd);
- gen_helper_vsetvl(dst, tcg_env, s1, s2, tcg_constant_tl(0));
+ if (vsetvl_inline_vtype(s, vtype)) {
+ unsigned vsew = FIELD_EX64(vtype, VTYPE, VSEW);
+ unsigned vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, vsew, 0);
+ unsigned vl = MIN(avl, vlmax);
+
+ if (avl > vlmax && avl < 2 * vlmax && s->cfg_ptr->rvv_vl_half_avl) {
+ vl = (avl + 1) >> 1;
+ }
+ tcg_gen_movi_tl(dst, vl);
+ gen_vsetvl_inline_state(tcg_constant_tl(vl), vtype);
+ } else {
+ gen_helper_vsetvl(dst, tcg_env, tcg_constant_tl(avl),
+ tcg_constant_tl(vtype), tcg_constant_tl(0));
+ }
gen_set_gpr(s, rd, dst);
finalize_rvv_inst(s);
gen_update_pc(s, s->cur_insn_len);
@@ -249,15 +281,48 @@ static bool trans_vsetvl(DisasContext *s, arg_vsetvl *a)
static bool trans_vsetvli(DisasContext *s, arg_vsetvli *a)
{
- TCGv s2 = tcg_constant_tl(a->zimm);
- return do_vsetvl(s, a->rd, a->rs1, s2);
+ TCGv avl, vl;
+ unsigned vsew, vlmax;
+
+ /* The x0 AVL encodings retain the helper's special VILL semantics. */
+ if (a->rs1 == 0 || !vsetvl_inline_vtype(s, a->zimm)) {
+ return do_vsetvl(s, a->rd, a->rs1, tcg_constant_tl(a->zimm));
+ }
+ if (!require_rvv(s) || !s->cfg_ptr->ext_zve32x) {
+ return false;
+ }
+
+ avl = get_gpr(s, a->rs1, EXT_ZERO);
+ vl = tcg_temp_new();
+ vsew = FIELD_EX64(a->zimm, VTYPE, VSEW);
+ vlmax = vext_get_vlmax(s->cfg_ptr->vlenb, vsew, 0);
+ tcg_gen_umin_tl(vl, avl, tcg_constant_tl(vlmax));
+ if (s->cfg_ptr->rvv_vl_half_avl) {
+ TCGv half = tcg_temp_new();
+
+ /* Overflow of AVL+1 is harmless outside the selected small range. */
+ tcg_gen_addi_tl(half, avl, 1);
+ tcg_gen_shri_tl(half, half, 1);
+ tcg_gen_movcond_tl(TCG_COND_LTU, half, avl,
+ tcg_constant_tl(2 * vlmax), half,
+ tcg_constant_tl(vlmax));
+ tcg_gen_movcond_tl(TCG_COND_LEU, vl, avl,
+ tcg_constant_tl(vlmax), avl, half);
+ }
+
+ /* Compute VL before writing rd, which may alias the AVL register. */
+ gen_vsetvl_inline_state(vl, a->zimm);
+ gen_set_gpr(s, a->rd, vl);
+ finalize_rvv_inst(s);
+ gen_update_pc(s, s->cur_insn_len);
+ lookup_and_goto_ptr(s);
+ s->base.is_jmp = DISAS_NORETURN;
+ return true;
}
static bool trans_vsetivli(DisasContext *s, arg_vsetivli *a)
{
- TCGv s1 = tcg_constant_tl(a->rs1);
- TCGv s2 = tcg_constant_tl(a->zimm);
- return do_vsetivli(s, a->rd, s1, s2);
+ return do_vsetivli(s, a->rd, a->rs1, a->zimm);
}
/* vector register offset from env */
--
2.47.0.windows.1