Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion crates/synth-synthesis/src/optimizer_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,17 @@ impl OptimizerBridge {
// Helper to get ARM reg from virtual reg.
// Also checks spill slots — if a vreg was spilled, returns R12 (IP scratch).
// Callers should also call `reload_spill` to emit the actual load instruction.
//
// PANICS if the vreg is neither mapped nor spilled. The previous behavior was
// a silent `Reg::R0` fallback, which produced miscompilation: a downstream
// instruction reading the "unknown" vreg would silently consume whatever
// R0 happens to hold (often a live caller param or memset's dest pointer).
// Issue #93 was exactly this — `wasm_to_ir` had no handler for
// `I64ExtendI32U`/`I64ExtendI32S`/`I32WrapI64`, so the IR they should have
// produced never got mapped to ARM regs, and downstream i64 shifts read R0
// as their `rm_lo`/`rm_hi`, destroying the loop counter on real silicon.
// A loud panic here is strictly better than a quiet miscompilation —
// crash the compiler, not the firmware.
let get_arm_reg =
|vreg: &OptReg, map: &HashMap<u32, Reg>, spills: &HashMap<u32, i32>| -> Reg {
if let Some(&r) = map.get(&vreg.0) {
Expand All @@ -1439,7 +1450,12 @@ impl OptimizerBridge {
// Will be reloaded into R12 by reload_spill
Reg::R12
} else {
Reg::R0
panic!(
"synth internal compiler error: vreg v{} has no assigned \
ARM register and no spill slot. This is a wasm_to_ir bug — \
likely a wasm op whose result is unmapped (see issue #93).",
vreg.0
);
}
};

Expand Down
Loading