Discovery
The cargo-fuzz harness i64_lowering_doesnt_clobber_params (PR #100, currently in CI) found this AAPCS-clobber regression as soon as it ran. Crash signature:
assertion left != right failed: AAPCS clobber: ARM instr at wasm line 1 writes
param reg R0 before LocalGet(0) at line 4.
Op: I64SetCond { rd: R0, rn_lo: R0, rn_hi: R1, rm_lo: R2, rm_hi: R3, cond: LT }
Reproduction
let wasm = vec![
WasmOp::I64Const(0), // produces hi:lo
// ... arrangement that synthesizes I64SetCond ...
WasmOp::LocalGet(0),
];
When wasm pushes an i64 constant and an i64 comparison op runs before a LocalGet(0) that reads R0 (the first param under AAPCS), I64SetCond writes R0 with the comparison result — destroying the param.
Root cause hypothesis
I64SetCond { rn_lo: R0, rn_hi: R1, rm_lo: R2, rm_hi: R3 } is the legacy hardcoded-register pattern that the v0.1.1 #86 fix replaced for I64Const-in-i64-ops via the alloc_i64_pair helper. The fix wasn't applied to I64SetCond (and presumably I64Eqz, I64Cmp, etc — the other i64 ops that use R0..R3 directly).
Scope
Same shape as the v0.1.1 fix, different ops. The optimized lowering path in optimizer_bridge::ir_to_arm needs every i64 op that touches R0..R3 to go through alloc_i64_pair (or an equivalent helper that respects the AAPCS param reserved set).
Candidate ops to audit:
- I64SetCond (confirmed by fuzz)
- I64Eqz
- All other I64Cmp variants
- Anything else where ir_to_arm hardcodes R0:R1 / R2:R3
Relation to existing work
Recommended fix
Apply the alloc_i64_pair-style register allocation to every i64 op in optimizer_bridge::ir_to_arm. Audit, don't whack-a-mole.
Bug class flag
#bug #aapcs #i64 #regalloc
Discovery
The cargo-fuzz harness
i64_lowering_doesnt_clobber_params(PR #100, currently in CI) found this AAPCS-clobber regression as soon as it ran. Crash signature:Reproduction
When wasm pushes an i64 constant and an i64 comparison op runs before a
LocalGet(0)that reads R0 (the first param under AAPCS),I64SetCondwrites R0 with the comparison result — destroying the param.Root cause hypothesis
I64SetCond { rn_lo: R0, rn_hi: R1, rm_lo: R2, rm_hi: R3 }is the legacy hardcoded-register pattern that the v0.1.1 #86 fix replaced forI64Const-in-i64-ops via thealloc_i64_pairhelper. The fix wasn't applied toI64SetCond(and presumablyI64Eqz,I64Cmp, etc — the other i64 ops that use R0..R3 directly).Scope
Same shape as the v0.1.1 fix, different ops. The optimized lowering path in
optimizer_bridge::ir_to_armneeds every i64 op that touches R0..R3 to go throughalloc_i64_pair(or an equivalent helper that respects the AAPCS param reserved set).Candidate ops to audit:
Relation to existing work
Recommended fix
Apply the
alloc_i64_pair-style register allocation to every i64 op inoptimizer_bridge::ir_to_arm. Audit, don't whack-a-mole.Bug class flag
#bug#aapcs#i64#regalloc