fix(riscv): signed-div overflow guard must not clobber the dividend (#232, v0.11.27) - #233
Merged
Merged
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
gale #232 — v0.11.26 regression: silent miscompile on signed div-by-const
Introduced by #231 (lowest-free allocator). The
i32.div_sINT_MIN / -1overflow guard pops its dividend/divisor off the vstack, then allocates scratch registers for theINT_MINand-1comparison constants. Because the popped operands are no longer on the vstack,live_regsdidn't protect them — the lowest-free allocator reused the dividend's register for theINT_MINconstant, clobbering it before the guard'sbne rs1, tminread it.filter_axis_decide(1000,100,500)→ 0 (expected 1088) on qemu_riscv32. Round-robin (v0.11.25) had marched to a different register and masked the latent defect — same lesson as before: an allocation-order change can expose a latent bug without being its root cause.Fix
New
alloc_temp_avoiding(&[Reg]): the guard materializes its constants into a register that avoids the popped-but-live dividend/divisor. Applied to:INT64_MIN / -1guard — same latent defect, though i64div_sis currently unreachable (i64 params/locals unimplemented), so it's defensive. (The broader i64 magnitude-reduction register discipline should be re-verified when i64 params land — noted, not claimed-fixed here.)Same liveness-across-a-branch-region class as #226.
Oracle
scripts/repro/signed_div_const.{wat,wasm}+signed_div_const_riscv_differential.py: 5/5 vectors match wasmtime — the 1088 repro, theINT_MINoverflow edge (-2147483648/?), and negative dividends.signed_div_guard_does_not_clobber_operands_232.div_const/control_step/flight_seam; RV32control_step/controller_step). The cleanup(riscv): allocator prefers caller-saved (lowest-free, not round-robin) (#230, v0.11.26) #231 caller-saved win is preserved — leaf functions still spill 0 callee-saved registers.Closes #232.
🤖 Generated with Claude Code