Skip to content

Commit ff4e843

Browse files
avrabeclaude
andauthored
chore(release): v0.11.42 — #313 if/else-with-result reconciliation bug-fix (#346)
gale #313: an `if (result …)` with asymmetric arms silently miscompiled — both arms' results piled onto the vstack and End read the else-arm register unconditionally, so the then-path (which branches over the else-arm) returned a register it never wrote. Fixed in #342 by checkpointing the vstack at If, reserving the then-arm results across the else-arm, and reconciling onto a single register at End (mov on the else path; nothing when the arms agree -> frozen fixtures byte-identical). Also #344 (CI std::hint::black_box after the #339 criterion 0.8 bump deprecated criterion::black_box). Workspace pin sweep 0.11.41 -> 0.11.42 across all 11 manifests + MODULE.bazel + Cargo.lock. Falsification statement in the changelog. Closes #313. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 856eb70 commit ff4e843

13 files changed

Lines changed: 77 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.11.42] - 2026-06-14
11+
12+
**IF/ELSE-WITH-RESULT RECONCILIATION BUG-FIX — gale #313: asymmetric arms
13+
silently miscompiled (then-path returned garbage); now fixed.**
14+
15+
- **if/else-with-result register reconciliation** (#313): `select_with_stack`'s
16+
`If`/`Else`/`End` lowering tracked the operand stack textually through both
17+
arms with no checkpoint at `If`, no restore at `Else`, and no reconciliation at
18+
`End`. For an `if (result …)` with asymmetric arms the two arms' results piled
19+
onto the vstack and `End` read the top (the else-arm's register)
20+
**unconditionally**, so the then-path — which branches over the else-arm —
21+
returned a register it never wrote (silent wrong-code, the #311/#331 class).
22+
Fix: checkpoint the vstack depth at `If`; at `Else` capture the then-arm's
23+
result registers and reserve them across the else-arm (reproducing the buggy
24+
code's incidental on-vstack protection, which is what keeps register-symmetric
25+
if/else byte-identical); at `End` reconcile the else-arm's result into the
26+
then-arm's register with a `MOV R_then, R_else` on the else path, emitting
27+
**nothing** when the arms already agree. No decoder/enum change — the result
28+
arity is observable from the vstack depth. A spilled or width-mismatched arm
29+
returns the ladder-recoverable exhaustion `Err` (retried/skipped, never
30+
miscompiled). Regression fixture `scripts/repro/u64_unpack_if.wat` +
31+
differential (`check_call(3,4) = 8`, was 0); the four frozen differentials
32+
(control_step 0x00210A55, flight_seam 0x07FDF307, div_const 338/338,
33+
mutex_pressure) stay **byte-identical** (none contains an `if`-with-result).
34+
35+
**Falsification:** this fix is wrong if a re-decode of any `if (result …)` with
36+
asymmetric arms still shows `End`/return reading the else-arm's register on the
37+
then path, or if `check_call(3,4)` on `u64_unpack_if.wat` returns anything but
38+
8 on silicon. (The RISC-V selector has the same gap — tracked as #343, not
39+
fixed here.)
40+
41+
- **CI: `std::hint::black_box`** (#344): criterion (bumped to 0.8.2 in #339)
42+
deprecated `criterion::black_box`; stable-clippy's `-D warnings` then failed
43+
the synth-opt bench on every PR. Imported `black_box` from `std::hint`.
44+
1045
## [0.11.41] - 2026-06-13
1146

1247
**SPILL-SLOT COLLISION BUG-FIX — gale #331: dissolved `k_mutex_unlock`

Cargo.lock

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ resolver = "2"
2727
# semver to publish, so the convention now catches up: workspace
2828
# version follows the release tag, bumped pre-tag in the release
2929
# checklist. See docs/release-process.md.
30-
version = "0.11.41"
30+
version = "0.11.42"
3131
edition = "2024"
3232
rust-version = "1.88"
3333
authors = ["PulseEngine Team"]

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module(
77
name = "synth",
88
# Kept in lockstep with [workspace.package] version in Cargo.toml.
99
# Both are bumped pre-tag — see docs/release-process.md.
10-
version = "0.11.41",
10+
version = "0.11.42",
1111
)
1212

1313
# Bazel dependencies

crates/synth-backend-awsm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ categories.workspace = true
1111
description = "aWsm backend integration for the Synth compiler"
1212

1313
[dependencies]
14-
synth-core = { path = "../synth-core", version = "0.11.41" }
14+
synth-core = { path = "../synth-core", version = "0.11.42" }
1515
anyhow.workspace = true
1616
thiserror.workspace = true

crates/synth-backend-riscv/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ categories.workspace = true
1111
description = "RISC-V encoder, ELF builder, PMP allocator, and bare-metal startup for synth"
1212

1313
[dependencies]
14-
synth-core = { path = "../synth-core", version = "0.11.41" }
15-
synth-synthesis = { path = "../synth-synthesis", version = "0.11.41" }
14+
synth-core = { path = "../synth-core", version = "0.11.42" }
15+
synth-synthesis = { path = "../synth-synthesis", version = "0.11.42" }
1616
anyhow.workspace = true
1717
thiserror.workspace = true
1818
tracing.workspace = true

crates/synth-backend-wasker/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ categories.workspace = true
1111
description = "Wasker backend integration for the Synth compiler"
1212

1313
[dependencies]
14-
synth-core = { path = "../synth-core", version = "0.11.41" }
14+
synth-core = { path = "../synth-core", version = "0.11.42" }
1515
anyhow.workspace = true
1616
thiserror.workspace = true

crates/synth-backend/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ default = ["arm-cortex-m"]
1515
arm-cortex-m = ["synth-synthesis"]
1616

1717
[dependencies]
18-
synth-core = { path = "../synth-core", version = "0.11.41" }
19-
synth-synthesis = { path = "../synth-synthesis", version = "0.11.41", optional = true }
18+
synth-core = { path = "../synth-core", version = "0.11.42" }
19+
synth-synthesis = { path = "../synth-synthesis", version = "0.11.42", optional = true }
2020
anyhow.workspace = true
2121
thiserror.workspace = true

crates/synth-cli/Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,18 @@ verify = ["synth-verify"]
2727
# Path deps carry `version` so `cargo publish` rewrites them to the
2828
# crates.io coordinate. Bumping the workspace version requires
2929
# updating these in lockstep — see docs/release-process.md.
30-
synth-core = { path = "../synth-core", version = "0.11.41" }
31-
synth-frontend = { path = "../synth-frontend", version = "0.11.41" }
32-
synth-synthesis = { path = "../synth-synthesis", version = "0.11.41" }
33-
synth-backend = { path = "../synth-backend", version = "0.11.41" }
30+
synth-core = { path = "../synth-core", version = "0.11.42" }
31+
synth-frontend = { path = "../synth-frontend", version = "0.11.42" }
32+
synth-synthesis = { path = "../synth-synthesis", version = "0.11.42" }
33+
synth-backend = { path = "../synth-backend", version = "0.11.42" }
3434

3535
# Optional external backends
36-
synth-backend-awsm = { path = "../synth-backend-awsm", version = "0.11.41", optional = true }
37-
synth-backend-wasker = { path = "../synth-backend-wasker", version = "0.11.41", optional = true }
38-
synth-backend-riscv = { path = "../synth-backend-riscv", version = "0.11.41", optional = true }
36+
synth-backend-awsm = { path = "../synth-backend-awsm", version = "0.11.42", optional = true }
37+
synth-backend-wasker = { path = "../synth-backend-wasker", version = "0.11.42", optional = true }
38+
synth-backend-riscv = { path = "../synth-backend-riscv", version = "0.11.42", optional = true }
3939

4040
# Optional verification (requires z3)
41-
synth-verify = { path = "../synth-verify", version = "0.11.41", optional = true, features = ["z3-solver", "arm"] }
41+
synth-verify = { path = "../synth-verify", version = "0.11.42", optional = true, features = ["z3-solver", "arm"] }
4242

4343
# Optional PulseEngine WASM optimizer
4444
# Uncomment when loom crate is available:

crates/synth-frontend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ description = "WASM/WAT parser and module decoder frontend for the Synth compile
1414
# Internal path deps carry an explicit version so `cargo publish`
1515
# can rewrite to the crates.io coordinate. `path` is used for
1616
# in-workspace builds; `version` is what crates.io sees.
17-
synth-core = { path = "../synth-core", version = "0.11.41" }
17+
synth-core = { path = "../synth-core", version = "0.11.42" }
1818

1919
wasmparser.workspace = true
2020
wasm-encoder.workspace = true

0 commit comments

Comments
 (0)