diff --git a/CHANGELOG.md b/CHANGELOG.md index 7157cd2..ae4c225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.15.1] - 2026-06-24 + +**Bug-fix: local promotion must never CAUSE a compile failure (#474).** v0.14.0 +made i32 local promotion default-on; it pins eligible locals into callee-saved +r4-r8, which halves the operand-stack temp pool. On a dense function that tips +register allocation past what it can recover, turning a working compile into a hard +`register exhaustion` skip — a regression from v0.12.0. + +The exhaustion-recovery ladder in `arm_backend.rs` is now parameterized on +promotion: it runs **with promotion first** — so every function that compiles today +is **bit-identical** (the frozen byte gate is unchanged: control_step `0x00210A55`, +flat+inlined flight_algo `0x07FDF307`, the div seam all preserved) — and, only if it +still ends in register exhaustion, falls back to the **promotion-off ladder** +automatically (the v0.12.0 frame-slot lowering, exactly what `SYNTH_NO_LOCAL_PROMOTE=1` +does by hand). Promotion is an optimization; it must never be the *reason* a +function fails to compile. The fallback keys on `register exhaustion` generally, so +it covers both the single-register and i64-spill-pool exhaustion classes promotion +can trigger. + +Verified: a generic repro (`scripts/repro/promotion_exhaustion_fallback.wat`) fails +to compile without the fix and compiles with it, `.text` byte-identical to the +promotion-off build; new CI regression test `promotion_never_causes_compile_failure_474`. +Also adds an analysis-only map of the full register-exhaustion recovery ladder +(`scripts/repro/register_exhaustion_recovery_ladder.md`) — the patch surface the +VCR-RA verified allocator (#242) must subsume — and the optimized-path ABI-model note +(#470, by-design non-AAPCS self-contained path). + ## [0.15.0] - 2026-06-24 **Immediate-shift folding is now DEFAULT-ON (VCR-RA, #390, epic #242).** The stack diff --git a/Cargo.lock b/Cargo.lock index ec86c7a..bb86d3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2023,14 +2023,14 @@ dependencies = [ [[package]] name = "synth-abi" -version = "0.15.0" +version = "0.15.1" dependencies = [ "synth-wit", ] [[package]] name = "synth-analysis" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "synth-core", @@ -2039,7 +2039,7 @@ dependencies = [ [[package]] name = "synth-backend" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "synth-core", @@ -2049,7 +2049,7 @@ dependencies = [ [[package]] name = "synth-backend-awsm" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "synth-core", @@ -2058,7 +2058,7 @@ dependencies = [ [[package]] name = "synth-backend-riscv" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "proptest", @@ -2070,7 +2070,7 @@ dependencies = [ [[package]] name = "synth-backend-wasker" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "synth-core", @@ -2079,11 +2079,11 @@ dependencies = [ [[package]] name = "synth-cfg" -version = "0.15.0" +version = "0.15.1" [[package]] name = "synth-cli" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "clap", @@ -2108,7 +2108,7 @@ dependencies = [ [[package]] name = "synth-core" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "gimli", @@ -2122,7 +2122,7 @@ dependencies = [ [[package]] name = "synth-frontend" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "synth-core", @@ -2136,14 +2136,14 @@ dependencies = [ [[package]] name = "synth-memory" -version = "0.15.0" +version = "0.15.1" dependencies = [ "bitflags", ] [[package]] name = "synth-opt" -version = "0.15.0" +version = "0.15.1" dependencies = [ "criterion", "synth-cfg", @@ -2151,11 +2151,11 @@ dependencies = [ [[package]] name = "synth-qemu" -version = "0.15.0" +version = "0.15.1" [[package]] name = "synth-synthesis" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "proptest", @@ -2170,7 +2170,7 @@ dependencies = [ [[package]] name = "synth-test" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "clap", @@ -2186,7 +2186,7 @@ dependencies = [ [[package]] name = "synth-verify" -version = "0.15.0" +version = "0.15.1" dependencies = [ "anyhow", "chrono", @@ -2204,7 +2204,7 @@ dependencies = [ [[package]] name = "synth-wit" -version = "0.15.0" +version = "0.15.1" [[package]] name = "tempfile" diff --git a/Cargo.toml b/Cargo.toml index ea78102..1f2a914 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ resolver = "2" # semver to publish, so the convention now catches up: workspace # version follows the release tag, bumped pre-tag in the release # checklist. See docs/release-process.md. -version = "0.15.0" +version = "0.15.1" edition = "2024" rust-version = "1.88" authors = ["PulseEngine Team"] diff --git a/MODULE.bazel b/MODULE.bazel index 32e2907..c61d645 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,7 +7,7 @@ module( name = "synth", # Kept in lockstep with [workspace.package] version in Cargo.toml. # Both are bumped pre-tag — see docs/release-process.md. - version = "0.15.0", + version = "0.15.1", ) # Bazel dependencies diff --git a/crates/synth-backend-awsm/Cargo.toml b/crates/synth-backend-awsm/Cargo.toml index eee3266..1a12dbe 100644 --- a/crates/synth-backend-awsm/Cargo.toml +++ b/crates/synth-backend-awsm/Cargo.toml @@ -11,6 +11,6 @@ categories.workspace = true description = "aWsm backend integration for the Synth compiler" [dependencies] -synth-core = { path = "../synth-core", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } anyhow.workspace = true thiserror.workspace = true diff --git a/crates/synth-backend-riscv/Cargo.toml b/crates/synth-backend-riscv/Cargo.toml index ab3206c..ac759b7 100644 --- a/crates/synth-backend-riscv/Cargo.toml +++ b/crates/synth-backend-riscv/Cargo.toml @@ -11,8 +11,8 @@ categories.workspace = true description = "RISC-V encoder, ELF builder, PMP allocator, and bare-metal startup for synth" [dependencies] -synth-core = { path = "../synth-core", version = "0.15.0" } -synth-synthesis = { path = "../synth-synthesis", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } +synth-synthesis = { path = "../synth-synthesis", version = "0.15.1" } anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/synth-backend-wasker/Cargo.toml b/crates/synth-backend-wasker/Cargo.toml index a25ffc0..0e91156 100644 --- a/crates/synth-backend-wasker/Cargo.toml +++ b/crates/synth-backend-wasker/Cargo.toml @@ -11,6 +11,6 @@ categories.workspace = true description = "Wasker backend integration for the Synth compiler" [dependencies] -synth-core = { path = "../synth-core", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } anyhow.workspace = true thiserror.workspace = true diff --git a/crates/synth-backend/Cargo.toml b/crates/synth-backend/Cargo.toml index 1d1e809..e7ccaae 100644 --- a/crates/synth-backend/Cargo.toml +++ b/crates/synth-backend/Cargo.toml @@ -15,7 +15,7 @@ default = ["arm-cortex-m"] arm-cortex-m = ["synth-synthesis"] [dependencies] -synth-core = { path = "../synth-core", version = "0.15.0" } -synth-synthesis = { path = "../synth-synthesis", version = "0.15.0", optional = true } +synth-core = { path = "../synth-core", version = "0.15.1" } +synth-synthesis = { path = "../synth-synthesis", version = "0.15.1", optional = true } anyhow.workspace = true thiserror.workspace = true diff --git a/crates/synth-cli/Cargo.toml b/crates/synth-cli/Cargo.toml index c8df4a0..9d859b0 100644 --- a/crates/synth-cli/Cargo.toml +++ b/crates/synth-cli/Cargo.toml @@ -27,18 +27,18 @@ verify = ["synth-verify"] # Path deps carry `version` so `cargo publish` rewrites them to the # crates.io coordinate. Bumping the workspace version requires # updating these in lockstep — see docs/release-process.md. -synth-core = { path = "../synth-core", version = "0.15.0" } -synth-frontend = { path = "../synth-frontend", version = "0.15.0" } -synth-synthesis = { path = "../synth-synthesis", version = "0.15.0" } -synth-backend = { path = "../synth-backend", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } +synth-frontend = { path = "../synth-frontend", version = "0.15.1" } +synth-synthesis = { path = "../synth-synthesis", version = "0.15.1" } +synth-backend = { path = "../synth-backend", version = "0.15.1" } # Optional external backends -synth-backend-awsm = { path = "../synth-backend-awsm", version = "0.15.0", optional = true } -synth-backend-wasker = { path = "../synth-backend-wasker", version = "0.15.0", optional = true } -synth-backend-riscv = { path = "../synth-backend-riscv", version = "0.15.0", optional = true } +synth-backend-awsm = { path = "../synth-backend-awsm", version = "0.15.1", optional = true } +synth-backend-wasker = { path = "../synth-backend-wasker", version = "0.15.1", optional = true } +synth-backend-riscv = { path = "../synth-backend-riscv", version = "0.15.1", optional = true } # Optional verification (requires z3) -synth-verify = { path = "../synth-verify", version = "0.15.0", optional = true, features = ["z3-solver", "arm"] } +synth-verify = { path = "../synth-verify", version = "0.15.1", optional = true, features = ["z3-solver", "arm"] } # Optional PulseEngine WASM optimizer # Uncomment when loom crate is available: diff --git a/crates/synth-frontend/Cargo.toml b/crates/synth-frontend/Cargo.toml index 820b6ed..c4e75ac 100644 --- a/crates/synth-frontend/Cargo.toml +++ b/crates/synth-frontend/Cargo.toml @@ -14,7 +14,7 @@ description = "WASM/WAT parser and module decoder frontend for the Synth compile # Internal path deps carry an explicit version so `cargo publish` # can rewrite to the crates.io coordinate. `path` is used for # in-workspace builds; `version` is what crates.io sees. -synth-core = { path = "../synth-core", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } wasmparser.workspace = true wasm-encoder.workspace = true diff --git a/crates/synth-opt/Cargo.toml b/crates/synth-opt/Cargo.toml index 7f2dbb6..e436050 100644 --- a/crates/synth-opt/Cargo.toml +++ b/crates/synth-opt/Cargo.toml @@ -11,7 +11,7 @@ categories.workspace = true description = "Peephole optimization passes for the Synth compiler" [dependencies] -synth-cfg = { path = "../synth-cfg", version = "0.15.0" } +synth-cfg = { path = "../synth-cfg", version = "0.15.1" } [dev-dependencies] criterion = { version = "0.8", features = ["html_reports"] } diff --git a/crates/synth-synthesis/Cargo.toml b/crates/synth-synthesis/Cargo.toml index 7c1a072..b375015 100644 --- a/crates/synth-synthesis/Cargo.toml +++ b/crates/synth-synthesis/Cargo.toml @@ -11,9 +11,9 @@ categories.workspace = true description = "WASM-to-ARM instruction selection and peephole optimizer" [dependencies] -synth-core = { path = "../synth-core", version = "0.15.0" } -synth-cfg = { path = "../synth-cfg", version = "0.15.0" } -synth-opt = { path = "../synth-opt", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } +synth-cfg = { path = "../synth-cfg", version = "0.15.1" } +synth-opt = { path = "../synth-opt", version = "0.15.1" } serde.workspace = true anyhow.workspace = true thiserror.workspace = true diff --git a/crates/synth-verify/Cargo.toml b/crates/synth-verify/Cargo.toml index e3204cb..bfa758d 100644 --- a/crates/synth-verify/Cargo.toml +++ b/crates/synth-verify/Cargo.toml @@ -17,12 +17,12 @@ arm = ["synth-synthesis"] [dependencies] # Core dependencies (always required) -synth-core = { path = "../synth-core", version = "0.15.0" } -synth-cfg = { path = "../synth-cfg", version = "0.15.0" } -synth-opt = { path = "../synth-opt", version = "0.15.0" } +synth-core = { path = "../synth-core", version = "0.15.1" } +synth-cfg = { path = "../synth-cfg", version = "0.15.1" } +synth-opt = { path = "../synth-opt", version = "0.15.1" } # ARM synthesis (optional, behind 'arm' feature) -synth-synthesis = { path = "../synth-synthesis", version = "0.15.0", optional = true } +synth-synthesis = { path = "../synth-synthesis", version = "0.15.1", optional = true } # SMT solver for formal verification z3 = { version = "0.19", features = ["static-link-z3"], optional = true }