Problem
Spike models per-hart VLEN faithfully. But a byte-for-byte whole-register
vector save/restore — the exact pattern an OS uses to save/restore V state
across a context switch — silently drops most of the register file when the
saving hart and the restoring hart have different VLEN, with no trap and no
diagnostic. A vsetvli e8,m8; vse8.v save on a hart with vlenb=64 (VLEN=512)
writes a flat buffer using a 64-byte per-register stride; loading that same
buffer back with vsetvli e8,m8; vle8.v on a hart with vlenb=16 (VLEN=128)
reads it with a 16-byte stride, so the upper bytes are truncated and the
surviving bytes are reassembled across the wrong register boundaries. The
program continues with a corrupted vector register file and a success exit
status from the simulator.
Reproducer
Full source (~90 lines, no dependencies beyond the toolchain + Spike + pk):
reproducer/spike-corruption/xwidth_corruption.c and run.sh in the repo
linked below. The essence:
# compile (newlib bare-metal, rv64gcv)
riscv64-unknown-elf-gcc -march=rv64gcv -mabi=lp64d -O2 \
xwidth_corruption.c -o xwidth_corruption.elf
# shared save buffer (pk's syscall proxy has no O_CREAT, so pre-create it)
head -c 2064 /dev/zero > state.bin
# VLEN is selected via the Zvl extension in the ISA string (--varch is gone):
# save on a 512-bit hart, then restore the SAME buffer on a 128-bit hart
spike --isa=rv64gcv_zvl512b pk xwidth_corruption.elf save state.bin
spike --isa=rv64gcv_zvl128b pk xwidth_corruption.elf restore state.bin
The program fills the 32 vector registers with a known pattern, does the
kernel-style whole-state save on the wide hart, restores on the narrow hart,
then reports how many registers survived intact and how many bytes were lost.
Observed vs. expected
Observed (verbatim stdout, restore step):
[save] vlenb=64 (VLEN=512b) wrote 2048 bytes, golden=fd8f43f997b2ec83
[restore] vlenb=16 (VLEN=128b) src_vlenb=64 (VLEN=512b)
[restore] registers_intact=2/32 first_corrupt_reg=1 bytes_lost=1536
RESULT src_vlen=512 dst_vlen=128 intact=2/32 bytes_lost=1536 verdict=CORRUPT
Only 2 of 32 registers survive; 1536 bytes are lost — and nothing flags it. The
equal-width control in the same harness (save and restore both at VLEN=512)
restores 32/32 with 0 bytes lost, confirming the harness itself is sound and the
loss is purely a function of the VLEN change.
Expected: a strict model would surface the lossy reinterpretation rather than
let it pass silently — e.g. a trap or a diagnostic when whole-register vector
state is restored under a vlenb different from the one that produced the
buffer. (Spike cannot generally know a buffer's provenance, which is exactly
what the question below is about.)
Environment
- Spike (stock upstream
riscv-software-src/riscv-isa-sim), commit
de829033327fb5f34839b9946a213917186b6a4d — clean build, no local patches.
- Toolchain:
riscv64-unknown-elf-gcc 14.2.0 (newlib).
- Runtime:
riscv-pk (proxy kernel).
- Host: Linux x86_64.
Question
Is a trap or diagnostic for lossy cross-width vector state restore in scope for
Spike, or is this considered a spec-level gap (i.e. the architecture leaves the
save/restore contract entirely to software, and a functional ISA simulator is
not expected to flag it)?
Full context (a vector-width-virtualization study that this corruption motivates)
is at https://github.com/om-mahesh/riscv-vector-width-virtualization — reading it
is not required to evaluate this bug; the reproducer above is self-contained.
Problem
Spike models per-hart
VLENfaithfully. But a byte-for-byte whole-registervector save/restore — the exact pattern an OS uses to save/restore
Vstateacross a context switch — silently drops most of the register file when the
saving hart and the restoring hart have different
VLEN, with no trap and nodiagnostic. A
vsetvli e8,m8; vse8.vsave on a hart withvlenb=64(VLEN=512)writes a flat buffer using a 64-byte per-register stride; loading that same
buffer back with
vsetvli e8,m8; vle8.von a hart withvlenb=16(VLEN=128)reads it with a 16-byte stride, so the upper bytes are truncated and the
surviving bytes are reassembled across the wrong register boundaries. The
program continues with a corrupted vector register file and a success exit
status from the simulator.
Reproducer
Full source (~90 lines, no dependencies beyond the toolchain + Spike + pk):
reproducer/spike-corruption/xwidth_corruption.candrun.shin the repolinked below. The essence:
The program fills the 32 vector registers with a known pattern, does the
kernel-style whole-state save on the wide hart, restores on the narrow hart,
then reports how many registers survived intact and how many bytes were lost.
Observed vs. expected
Observed (verbatim stdout,
restorestep):Only 2 of 32 registers survive; 1536 bytes are lost — and nothing flags it. The
equal-width control in the same harness (
saveandrestoreboth at VLEN=512)restores 32/32 with 0 bytes lost, confirming the harness itself is sound and the
loss is purely a function of the VLEN change.
Expected: a strict model would surface the lossy reinterpretation rather than
let it pass silently — e.g. a trap or a diagnostic when whole-register vector
state is restored under a
vlenbdifferent from the one that produced thebuffer. (Spike cannot generally know a buffer's provenance, which is exactly
what the question below is about.)
Environment
riscv-software-src/riscv-isa-sim), commitde829033327fb5f34839b9946a213917186b6a4d— clean build, no local patches.riscv64-unknown-elf-gcc14.2.0 (newlib).riscv-pk(proxy kernel).Question
Is a trap or diagnostic for lossy cross-width vector state restore in scope for
Spike, or is this considered a spec-level gap (i.e. the architecture leaves the
save/restore contract entirely to software, and a functional ISA simulator is
not expected to flag it)?
Full context (a vector-width-virtualization study that this corruption motivates)
is at https://github.com/om-mahesh/riscv-vector-width-virtualization — reading it
is not required to evaluate this bug; the reproducer above is self-contained.