On Fri, Jul 24, 2026 at 11:01:45AM +0800, Zephyr Li wrote:
> A unit-stride fault-only-first load must leave vl unchanged when element zero 
> raises a synchronous exception. Keep the shortened value in a local bound 
> until all loads complete, and only then update the architectural vl.
> 
> Add a bare-metal RVV regression test which faults vle32ff.v on element zero 
> and checks that vl remains unchanged in the trap handler.
Please wrap the commit message at 76 columns or fewer.

see:
https://www.qemu.org/docs/master/devel/submitting-a-patch.html#write-a-meaningful-commit-message


Reviewed-by: Chao Liu <[email protected]>

Thanks,
Chao
> 
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3544
> Signed-off-by: Zephyr Li <[email protected]>
> ---
>  target/riscv/tcg/vector_helper.c          | 23 ++++++----
>  tests/tcg/riscv64/Makefile.softmmu-target |  5 ++
>  tests/tcg/riscv64/test-vle32ff.S          | 56 +++++++++++++++++++++++
>  3 files changed, 75 insertions(+), 9 deletions(-)
>  create mode 100644 tests/tcg/riscv64/test-vle32ff.S
> 
> diff --git a/target/riscv/tcg/vector_helper.c 
> b/target/riscv/tcg/vector_helper.c
> index e321ca2616..5a310822b7 100644
> --- a/target/riscv/tcg/vector_helper.c
> +++ b/target/riscv/tcg/vector_helper.c
> @@ -686,7 +686,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, 
> CPURISCVState *env,
>            uint32_t desc, vext_ldst_elem_fn_tlb *ldst_tlb,
>            vext_ldst_elem_fn_host *ldst_host, uint32_t log2_esz, uintptr_t ra)
>  {
> -    uint32_t i, k, vl = 0;
> +    uint32_t i, k, vl = 0, load_vl;
>      uint32_t nf = vext_nf(desc);
>      uint32_t vm = vext_vm(desc);
>      uint32_t max_elems = vext_max_elems(desc, log2_esz);
> @@ -752,22 +752,24 @@ vext_ldff(void *vd, void *v0, target_ulong base, 
> CPURISCVState *env,
>          }
>      }
>  ProbeSuccess:
> -    /* load bytes from guest memory */
> -    if (vl != 0) {
> -        env->vl = vl;
> -    }
> +    /*
> +     * Keep a shortened vl local until all loads complete. In particular,
> +     * an exception from element zero must leave the architectural vl alone.
> +     */
> +    load_vl = vl ? vl : env->vl;
>  
> -    if (env->vstart < env->vl) {
> +    if (env->vstart < load_vl) {
>          if (vm) {
>              /* Load/store elements in the first page */
>              if (likely(elems)) {
> +                elems = MIN(elems, load_vl - env->vstart);
>                  vext_page_ldst_us(env, vd, addr, elems, nf, max_elems,
>                                    log2_esz, true, mmu_index, ldst_tlb,
>                                    ldst_host, ra);
>              }
>  
>              /* Load/store elements in the second page */
> -            if (unlikely(env->vstart < env->vl)) {
> +            if (unlikely(env->vstart < load_vl)) {
>                  /* Cross page element */
>                  if (unlikely(page_split % msize)) {
>                      for (k = 0; k < nf; k++) {
> @@ -780,7 +782,7 @@ ProbeSuccess:
>  
>                  addr = base + ((env->vstart * nf) << log2_esz);
>                  /* Get number of elements of second page */
> -                elems = env->vl - env->vstart;
> +                elems = load_vl - env->vstart;
>  
>                  /* Load/store elements in the second page */
>                  vext_page_ldst_us(env, vd, addr, elems, nf, max_elems,
> @@ -788,7 +790,7 @@ ProbeSuccess:
>                                    ldst_host, ra);
>              }
>          } else {
> -            for (i = env->vstart; i < env->vl; i++) {
> +            for (i = env->vstart; i < load_vl; i++) {
>                  k = 0;
>                  while (k < nf) {
>                      if (!vext_elem_mask(v0, i)) {
> @@ -806,6 +808,9 @@ ProbeSuccess:
>              }
>          }
>      }
> +    if (vl != 0) {
> +        env->vl = vl;
> +    }
>      env->vstart = 0;
>  
>      vext_set_tail_elems_1s(env->vl, vd, desc, nf, esz, max_elems);
> diff --git a/tests/tcg/riscv64/Makefile.softmmu-target 
> b/tests/tcg/riscv64/Makefile.softmmu-target
> index 82be8a2c91..7ae225bd73 100644
> --- a/tests/tcg/riscv64/Makefile.softmmu-target
> +++ b/tests/tcg/riscv64/Makefile.softmmu-target
> @@ -41,5 +41,10 @@ comma:= ,
>  run-test-crc32: test-crc32
>       $(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<)
>  
> +EXTRA_RUNS += run-test-vle32ff
> +run-test-vle32ff: test-vle32ff
> +     $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true $(QEMU_OPTS)$<)
> +test-vle32ff: CFLAGS += -march=rv64gcv
> +
>  # We don't currently support the multiarch system tests
>  undefine MULTIARCH_TESTS
> diff --git a/tests/tcg/riscv64/test-vle32ff.S 
> b/tests/tcg/riscv64/test-vle32ff.S
> new file mode 100644
> index 0000000000..4c687bf1e4
> --- /dev/null
> +++ b/tests/tcg/riscv64/test-vle32ff.S
> @@ -0,0 +1,56 @@
> +/*
> + * Verify that a fault-only-first load keeps vl unchanged when element zero
> + * raises a synchronous exception.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +     .option norvc
> +
> +     .text
> +     .globl _start
> +_start:
> +     lla     t0, trap
> +     csrw    mtvec, t0
> +
> +     li      t1, 4
> +     vsetvli t2, t1, e32, m1, ta, ma
> +     li      t0, 1
> +     vle32ff.v       v1, (t0)
> +
> +     /* Element zero did not trap. */
> +     li      a0, 1
> +     j       _exit
> +
> +trap:
> +     csrr    t0, mcause
> +     li      t1, 5           /* Load access fault. */
> +     bne     t0, t1, trap_fail
> +
> +     csrr    t0, vl
> +     li      t1, 4
> +     bne     t0, t1, trap_fail
> +
> +     li      a0, 0
> +     j       _exit
> +
> +trap_fail:
> +     li      a0, 1
> +
> +_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 */
> +
> +     .balign 16
> +     slli    zero, zero, 0x1f
> +     ebreak
> +     srai    zero, zero, 0x7
> +     j       .
> +
> +     .data
> +     .balign 8
> +semiargs:
> +     .space  16

Reply via email to