Found while verifying #312 (PR #316) with the new RV32 behavioral oracle — strictly pre-existing: the probe doesn't even execute on the parent commit (UC_ERR_INSN_INVALID), and 6/6 vectors fail post-#312 with wrong signs.
Root cause: the i64 signed-division lowering allocates nsign/dsign temporaries, which land in t4/t5 — the udiv core's fixed DIV_D_LO/HI registers. The core's input parallel-move overwrites them before result_sign = nsign ^ dsign is computed, so e.g. divs(-100,3) = 0x1f where wasmtime says 0xffffffdf. The same fixed-register file (T0-T6/S1-S3) clobbers any live vstack value sitting there across an i64 div — the #312 per-op pin scope protects within an op but the div core's fixed file bypasses the allocator entirely.
Fix directions: (a) move the sign temporaries to S4-S6 (outside the core's fixed file), or (b) make the div core spill/restore around live values, or (c) give the core allocator-chosen registers. (a) is the bounded v1.
Evidence staged: /tmp/i64_divs.wat + /tmp/i64_divs_diff.py (6-vector unicorn-vs-wasmtime probe) — will commit as scripts/repro/ lane with the fix.
Same family as #232 (constants into the live numerator) and the #312 aliasing — all symptoms of fixed/blind register choices in hand-written lowerings; the structural cure is the VCR program (#242), this is the containment fix. Queue: after v0.11.37 tags (it's not a regression and the u64-decide pattern doesn't divide).
Found while verifying #312 (PR #316) with the new RV32 behavioral oracle — strictly pre-existing: the probe doesn't even execute on the parent commit (UC_ERR_INSN_INVALID), and 6/6 vectors fail post-#312 with wrong signs.
Root cause: the i64 signed-division lowering allocates
nsign/dsigntemporaries, which land in t4/t5 — the udiv core's fixedDIV_D_LO/HIregisters. The core's input parallel-move overwrites them beforeresult_sign = nsign ^ dsignis computed, so e.g.divs(-100,3) = 0x1fwhere wasmtime says0xffffffdf. The same fixed-register file (T0-T6/S1-S3) clobbers any live vstack value sitting there across an i64 div — the #312 per-op pin scope protects within an op but the div core's fixed file bypasses the allocator entirely.Fix directions: (a) move the sign temporaries to S4-S6 (outside the core's fixed file), or (b) make the div core spill/restore around live values, or (c) give the core allocator-chosen registers. (a) is the bounded v1.
Evidence staged:
/tmp/i64_divs.wat+/tmp/i64_divs_diff.py(6-vector unicorn-vs-wasmtime probe) — will commit asscripts/repro/lane with the fix.Same family as #232 (constants into the live numerator) and the #312 aliasing — all symptoms of fixed/blind register choices in hand-written lowerings; the structural cure is the VCR program (#242), this is the containment fix. Queue: after v0.11.37 tags (it's not a regression and the u64-decide pattern doesn't divide).