ldst_index_trans
Overview
ldst_index_trans() is a translation-time helper for indexed RISC-V vector
load/store instructions (the segment of the V extension whose addressing
combines a base register rs1 with an index vector vs2). It lives in
target/riscv/insn_trans/trans_rvv.c.inc, the QEMU TCG translation include
that materializes every RISC-V Vector instruction, and is part of a family of
helpers (ldst_us_trans, ldst_stride_trans, ldst_index_trans,
ldst_whole_trans) that share the same overall structure for unit-stride,
stride, indexed, and whole-register load/store variants.
Signature
From the diff in the patch evidence:
static bool ldst_index_trans(uint32_t vd, uint32_t rs1, uint32_t vs2,
uint32_t data, uint32_t is_store,
uint32_t is_load, uint32_t is_seg,
gen_helper_* fn, DisasContext *s)
{
...
fn(dest, mask, base, index, tcg_env, desc);
mark_vs_dirty(s);
gen_set_label(over);
return true;
}
The function takes the destination vector register vd, the scalar base
rs1, the index vector vs2, the data size, the load/store/segment flags,
the helper generator fn that emits the runtime helper call, and the
disassembly context s.
Behavior
- Validates
mstatus.VSagainst the current vector configuration and ensuresvl/vtype/EEW are consistent. If the instruction is illegal in the current context, the helper jumps to theoverexit label and returnstrue(the TB is finalized) without emitting any state-changing code. - Loads
rs1into a base address and resolves the per-elementvs2index vector intoindex. - Calls the generator function
fn(dest, mask, base, index, tcg_env, desc)that will lower to avext_ldst_*helper at runtime. - Calls
mark_vs_dirty(s)to record that vector state has changed. - Jumps to
gen_set_label(over)and returnstrue.
Why mark_vs_dirty() is called unconditionally
Before the fix, ldst_index_trans (and its three siblings) wrapped the
mark_vs_dirty() call in if (!is_store), on the assumption that only the
load path needed to mark vector state as Dirty. The patch
[PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too by
Daniel Henrique Barboza argues that this is wrong, citing RISC-V Vector
specification section 3.2:
"When mstatus.VS is set to Initial or Clean, executing any instruction that changes vector state, including the vector CSRs, will change mstatus.VS to Dirty."
A vector store writes the vstart CSR to zero after execution
(vext_ldst_us() in vector_helper.c), which is itself a vector-state CSR
change. Therefore both loads and stores executed through
ldst_index_trans alter vector state and must call mark_vs_dirty().
The fix removes the if (!is_store) guard:
- if (!is_store) {
- mark_vs_dirty(s);
- }
-
+ mark_vs_dirty(s);
gen_set_label(over);
return true;
The same change is applied in ldst_us_trans, ldst_stride_trans, and
ldst_whole_trans, dropping the file's net count by 15 lines (4 insertions,
15 deletions).
Related context
- Fixed-by commit: 8e1ee1fb57 — "target/riscv: rvv-1.0: add
translation-time vector context status", which originally introduced the
guarded
mark_vs_dirty()calls. - Patch author: Daniel Henrique Barboza
<dbarboza@ventanamicro.com>, posted to the QEMU devel list on 2024-02-16. - Sibling helpers using the same pattern:
ldst_us_trans,ldst_stride_trans,ldst_whole_trans. - Runtime counterpart:
vext_ldst_us()invector_helper.c, which is whereenv->vstartis reset to zero on store completion.
See also
mark_vs_dirty— the helper used to flagmstatus.VSas Dirty.trans_rvv.c.inc— the include file whereldst_index_transis defined.- RISC-V "V" Vector Extension, section 3.2 (mstatus.VS state transitions).