Skip to content

fix(opt): ir_to_arm returns Result — panic-free optimized path, fuzz re-gated#132

Merged
avrabe merged 4 commits into
mainfrom
fix/ir-to-arm-panic-free
May 23, 2026
Merged

fix(opt): ir_to_arm returns Result — panic-free optimized path, fuzz re-gated#132
avrabe merged 4 commits into
mainfrom
fix/ir-to-arm-panic-free

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 22, 2026

Summary

Makes synth's optimized ARM lowering path (ir_to_arm) panic-free on malformed input — the last remaining panic site in that pipeline — and re-promotes the wasm_ops_lower_or_error fuzz harness to gating. Closes debt open since v0.3.1.

Background

wasm_to_ir was hardened across v0.3.1/v0.4.0 (returns Result, pre-flight wasm_stack_check). But ir_to_arm's get_arm_reg closure still panic!'d on an unmapped vreg (the PR #101 defensive panic). Because of that, wasm_ops_lower_or_error was demoted to gating: false in PR #117 and never re-promoted.

Part 1 — ir_to_arm panic-free

The defensive check is not removed — it's converted panic→Err. A malformed-input case and a genuine internal bug both now yield a typed Err with the rich diagnostic. The harness contract ("lower or Err, never panic") is satisfied.

Part 2 — fuzz re-gated

.github/workflows/fuzz-smoke.yml: wasm_ops_lower_or_error flipped gating: falsegating: true; the issue-#121/PR-#117 demote comment replaced with a note that ir_to_arm now returns Result.

Part 3 — regression test

New crates/synth-synthesis/tests/regression_ir_to_arm_panic_free.rs, 5 tests: mixed i32 arith/shift, type-mismatched i64, i64-extend-into-shift, well-formed-program-lowers-to-Ok, and a hand-built IR instruction (Add with unproduced src vregs) that reaches get_arm_reg's defensive branch directly and confirms it yields Err (with a diagnostic-content assertion) rather than panicking.

Note: the optimize_full pre-flight catches WASM-op-level malformed shapes before ir_to_arm; the hand-built-IR test is what exercises the now-Err path directly.

Validation

  • cargo test --workspace --exclude synth-verify — 0 regressions (+5 tests).
  • cargo clippy --workspace --exclude synth-verify --all-targets -- -D warnings — clean.
  • cargo fmt --check — clean.

Test plan

  • CI green, including the now-gating wasm_ops_lower_or_error fuzz harness
  • No regression in AAPCS / i64 / optimized-path suites

🤖 Generated with Claude Code

avrabe and others added 2 commits May 22, 2026 20:13
`ir_to_arm`'s `get_arm_reg` closure panicked ("synth internal compiler
error: vreg vN has no assigned ARM register...") when an IR vreg had no
mapping and no spill slot. PR #101 introduced that panic — correct then
(a loud crash beats a silent R0-fallback miscompilation), but it was the
last remaining panic site in the optimized lowering path.

Convert the `panic!` into `Err(Error::synthesis(...))` carrying the same
issue-#93 diagnostic, and change `ir_to_arm`'s signature from
`Vec<ArmOp>` to `Result<Vec<ArmOp>>`. All 166 `get_arm_reg` call sites
propagate via `?`. The defensive check is preserved — a genuine
`wasm_to_ir` bug still surfaces as a rich typed error, it just no longer
kills the process.

Callers updated: `arm_backend.rs` folds the `ir_to_arm` step into the
existing `optimize_full` fallback so an `Err` falls back to the direct
selector (honest degradation, same as the issue-#120 float path); the
`wasm_ops_lower_or_error` fuzz harness skips on `Err`. New regression
test `regression_ir_to_arm_panic_free` confirms a hand-built IR with an
unmapped src vreg now yields `Err` (not a panic) and that the error
keeps its issue-#93 diagnostic content.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The harness was demoted to `gating: false` in PR #117 pending the
issue-#121 slot_stack refactor. That refactor landed, and the last panic
site in the optimized path — `ir_to_arm`'s defensive `get_arm_reg` — now
returns `Result` instead of `panic!`-ing. The whole `optimize_full` +
`ir_to_arm` path is panic-free, so the harness (contract: "lower or Err,
never panic") gates again. Update the matrix comment accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 76.61692% with 47 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/synth-synthesis/src/optimizer_bridge.rs 75.39% 47 Missing ⚠️

📢 Thoughts on this report? Let us know!

avrabe added 2 commits May 23, 2026 06:39
Sibling fix to the panic-free `ir_to_arm` work in this PR: the
`pop_i32_unary!` macro inside `wasm_to_ir` still used `.expect(...)`,
which the earlier slot_stack Result conversion missed because the
`.expect(...)` ended with `,` (the macro pattern) rather than `;` (the
statement pattern the original sed targeted).

The re-gated `wasm_ops_lower_or_error` fuzz harness — re-promoted to
gating in this PR — found a malformed input that slips past the
pre-flight check and reaches an i32 unary op via `pop_i32_unary!`,
triggering the leftover `.expect()` panic. Converted to
`.ok_or_else(...)?` matching `pop_i32_binary!`'s shape so the
function-level `Result` propagates instead of panicking.

This is exactly the bug class re-gating the harness exists to catch —
the gating fuzz did its job here.
The catch-all comment still described downstream consumers failing
'loudly via slot_stack.pop().expect(...)'. After the Result conversion
and the pop_i32_unary! macro fix in this PR, no .expect() remains;
unknown-op back-references now surface as a typed Err via
.ok_or_else(...)?. Same bug-finder semantics, different failure mode.
The comment now matches the code.
@avrabe
Copy link
Copy Markdown
Contributor Author

avrabe commented May 23, 2026

Two follow-ups pushed: b47eaae fixes the leftover pop_i32_unary! macro .expect(...) (my earlier Result conversion missed it because the macro body's .expect ended with , not ;); the re-gated fuzz caught it on the first run — exactly the bug class re-gating exists to find. c16e314 updates a stale catch-all comment to match the new Err propagation. Polling the rerun.

@avrabe avrabe merged commit a9adbc7 into main May 23, 2026
10 of 13 checks passed
@avrabe avrabe deleted the fix/ir-to-arm-panic-free branch May 23, 2026 08:30
avrabe added a commit that referenced this pull request May 23, 2026
v0.5.0 — verification & robustness:
- #133 validator pattern to full i32 + i64 surface (#76)
- #131 RV32 i64 div/rem (Phase 3 completes i64 integer)
- #132 panic-free ir_to_arm + macro fix + gating fuzz restored

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant