Skip to content
STIMSMITH

ldst_stride_trans

Technique WIKI v1 · 7/29/2026

ldst_stride_trans is a translation helper in QEMU's RISC-V vector (RVV) translator (target/riscv/insn_trans/trans_rvv.c.inc) that emits TCG code for RISC-V vector strided load/store instructions. Originally it conditionally called mark_vs_dirty() only on non-store paths, but a 2024 patch by Daniel Henrique Barboza removes the is_store guard so that mark_vs_dirty() is always invoked, matching the RVV spec's requirement that any instruction changing vector state must set mstatus.VS to Dirty (e.g. because stores zero env->vstart).

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/stores
  • ldst_stride_trans() — strided vector loads/stores
  • ldst_index_trans() — indexed vector loads/stores
  • ldst_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 register rs1, stride register rs2, 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 dirty
  • trans_rvv.c.inc — the inclusion unit in which ldst_stride_trans is defined

CITATIONS

6 sources
6 citations
[1] ldst_stride_trans originally called mark_vs_dirty() only when !is_store, guarded by an if statement. [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too
[2] The 2024 patch by Daniel Henrique Barboza removes the is_store guard so that mark_vs_dirty() is always called in ldst_stride_trans. [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too
[3] The change is motivated by RVV spec section 3.2, which requires mstatus.VS to become Dirty whenever vector state (including vector CSRs) is changed, regardless of whether the operation is a load or a store. [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too
[4] Store operations still change vector state because vext_ldst_us() in vector_helper.c resets env->vstart to zero after execution. [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too
[5] The same patch applies the analogous unconditional mark_vs_dirty() change to ldst_us_trans, ldst_index_trans, and ldst_whole_trans in target/riscv/insn_trans/trans_rvv.c.inc. [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too
[6] The patch fixes the regression introduced by commit 8e1ee1fb57 ("target/riscv: rvv-1.0: add translation-time vector context status"). [PATCH 1/3] trans_rvv.c.inc: write CSRs must call mark_vs_dirty() too