Overview
ldst_stride_trans() is a translation-time helper defined in target/riscv/insn_trans/trans_rvv.c.inc within QEMU's RISC-V vector (RVV) TCG translator. It emits the TCG sequence that realizes RISC-V vector strided load and store instructions (those that use an explicit per-element stride from an x register).
The helper is one of a family of related vector load/store translators in the same file:
ldst_us_trans()— unit-stride vector loads/storesldst_stride_trans()— strided vector loads/storesldst_index_trans()— indexed vector loads/storesldst_whole_trans()— whole-register vector loads/stores
Original behavior
In the version introduced by commit 8e1ee1fb57 ("target/riscv: rvv-1.0: add translation-time vector context status"), ldst_stride_trans() guarded the call to mark_vs_dirty() so that it was only executed on the non-store path:
c fn(dest, mask, base, stride, tcg_env, desc);
if (!is_store) { mark_vs_dirty(s); }
gen_set_label(over); return true;
The rationale at the time was that store-only executions were assumed not to change vector architectural state beyond memory, so the dirty bit was not raised.
Spec-driven change (2024)
A patch posted to the qemu-devel mailing list by Daniel Henrique Barboza on 16 February 2024 ([PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too) argues, citing RISC-V Vector spec section 3.2, that:
"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."
Even on a store path, ldst_stride_trans() changes vector state because vector store helpers (vext_ldst_us() in vector_helper.c) reset env->vstart to zero after execution. Resetting vstart is a write to a vector CSR, and therefore the execution is obligated to mark the vector context dirty regardless of whether the operation is a load or a store.
Resulting code
After the patch, the conditional is removed and mark_vs_dirty() is always called at the end of the generated TCG block, before jumping to the over label:
c fn(dest, mask, base, stride, tcg_env, desc);
mark_vs_dirty(s); gen_set_label(over); return true;
The same simplification is applied in parallel to ldst_us_trans(), ldst_index_trans(), and ldst_whole_trans() in the same patch (1 file, 4 insertions, 15 deletions).
Role in the translator
- File:
target/riscv/insn_trans/trans_rvv.c.inc - Signature (per the diff hunks):
static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, ...) - Inputs: destination vector register
vd, base address registerrs1, stride registerrs2, plus mask/MMU descriptor arguments - Effect: Generates TCG ops to compute a strided address sequence for each active element and invokes a runtime helper, then unconditionally marks the vector state dirty before terminating translation
See also
mark_vs_dirty— the helper used to flag the RVV context as dirtytrans_rvv.c.inc— the inclusion unit in whichldst_stride_transis defined