Skip to content

Commit 377b93e

Browse files
avrabeclaude
andauthored
feat(vcr-sel): ship cmp→select fusion default-on — v0.13.0 (VCR-SEL-004, #428, #242) (#454)
The byte-changing default-on flip the cmp→select arc has been building toward. ARM compare→select lowering now predicates the moves on the compare's own flags (`cmp; mov{c}; mov{invert(c)}`) instead of materializing+re-testing a boolean, −2 insns/select. .text shrinks on every function with a select (control_step 354→324, flight_seam 1016→902, flight_seam_flat 1240→1122; −262 B across the frozen fixtures); gale measured gust_mix 2.375×→2.125× vs LLVM. Results preserved — validated three independent ways BEFORE shipping: 1. named-anchor differentials re-run with fusion ON, same commit as the re-freeze: control_step still 0x00210A55 (13/13), flat+inlined flight_algo still 0x07FDF307. 2. unicorn execution oracle running the two-move mov{invert(c)} arm (cmp-select- oracle CI job, 11/11 off==on==wasmtime) — its unfused baseline now opts out via SYNTH_NO_CMP_SELECT_FUSE. 3. gale's gale_decider_diff sweep: 8 verified primitives, 10,596 cases, native ≡ unfused ≡ fused. - arm_backend.rs: fusion default-on; escape hatch SYNTH_NO_CMP_SELECT_FUSE=1. - frozen_codegen_bytes.rs: ARM goldens re-frozen to the fused .text (RV32 + signed_div_const unchanged — fusion is ARM-only / 0 sites); harness now locks the shipped (fused) path and removes the opt-out var. - version 0.12.0 → 0.13.0 (pin sweep: all path-deps + MODULE.bazel); CHANGELOG; VCR-SEL-004 status approved → implemented. Pending follow-up (gale, post-ship): on-silicon G474RE DWT cycle no-regression — user waived it as a release gate in favor of the qemu+sweep+oracle evidence. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e731446 commit 377b93e

17 files changed

Lines changed: 111 additions & 63 deletions

File tree

CHANGELOG.md

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

88
## [Unreleased]
99

10+
## [0.13.0] - 2026-06-24
11+
12+
**cmp→select fusion is now DEFAULT-ON (VCR-SEL-004, #428, epic #242).** The ARM
13+
backend's compare→select lowering no longer materializes a boolean and re-tests
14+
it (`cmp; SetCond; cmp #0; movne; moveq`); it predicates the moves directly on
15+
the compare's own flags (`cmp; mov{c}; mov{invert(c)}`), −2 instructions per
16+
select. This is a **byte-changing** release: `.text` shrinks on every function
17+
with a select (control_step 354→324 B, flight_seam 1016→902, flight_seam_flat
18+
1240→1122; −262 B across the frozen fixtures), and gale's `gust_mix` measured
19+
2.375×→2.125× vs LLVM with a 132→116 B function.
20+
21+
Execution **results are preserved** — validated three ways before shipping: (1)
22+
the named-anchor differentials re-run with fusion on (control_step still
23+
`0x00210A55`, flat+inlined flight_algo still `0x07FDF307`); (2) a unicorn
24+
execution oracle that runs the two-move `mov{invert(c)}` arm (`cmp-select-oracle`
25+
CI job, 11/11 result-identical); (3) gale's `gale_decider_diff` sweep across all
26+
8 verified primitives (10,596 cases, native ≡ unfused ≡ fused). The byte gates
27+
were re-frozen to the fused `.text` on this commit.
28+
29+
**Escape hatch:** `SYNTH_NO_CMP_SELECT_FUSE=1` reverts to the pre-fusion lowering.
30+
**Pending follow-up:** the on-silicon G474RE DWT cycle no-regression check is
31+
tracked post-ship (gale); the qemu `-icount` proxy showed a monotonic win.
32+
1033
## [0.12.0] - 2026-06-23
1134

1235
**DWARF SOURCE-LINE DEBUGGING — `--debug-line` (VCR-DBG-001, #394, epic #242).**

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.12.0"
30+
version = "0.13.0"
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.12.0",
10+
version = "0.13.0",
1111
)
1212

1313
# Bazel dependencies

artifacts/verified-codegen-roadmap.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,16 @@ artifacts:
737737
exhaustive sweep); precond (2) (G474RE silicon no-regression) still OWED —
738738
gale's bench is thumbv7m/qemu today — flip stays held on it (user call
739739
2026-06-23: keep the silicon gate; close the exec gap first).
740-
status: approved
740+
FLIP SHIPPED v0.13.0 (2026-06-24, #428): default-on landed. User authorized
741+
shipping on the qemu+sweep+oracle evidence and WAIVING precond (2) for the
742+
release (gale takes the on-silicon G474RE DWT no-regression as a tracked
743+
post-ship follow-up). Re-froze the fused .text on the same commit the
744+
named-anchor differentials were re-run on (control_step preserved 0x00210A55,
745+
flat+inlined flight_algo preserved 0x07FDF307; .text −262 B across the frozen
746+
fixtures). Escape hatch SYNTH_NO_CMP_SELECT_FUSE=1 reverts the lowering.
747+
SCOPE: the select half shipped; the br_if→predicated-branch half remains a
748+
separate follow-up (branch consumers unmodeled by reg_effect).
749+
status: implemented
741750
tags: [codegen, selector, peephole, compare-select, flag-fusion, gale-209, perf, track-b, vcr-oracle-001]
742751
links:
743752
- type: derives-from

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.12.0" }
14+
synth-core = { path = "../synth-core", version = "0.13.0" }
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.12.0" }
15-
synth-synthesis = { path = "../synth-synthesis", version = "0.12.0" }
14+
synth-core = { path = "../synth-core", version = "0.13.0" }
15+
synth-synthesis = { path = "../synth-synthesis", version = "0.13.0" }
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.12.0" }
14+
synth-core = { path = "../synth-core", version = "0.13.0" }
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.12.0" }
19-
synth-synthesis = { path = "../synth-synthesis", version = "0.12.0", optional = true }
18+
synth-core = { path = "../synth-core", version = "0.13.0" }
19+
synth-synthesis = { path = "../synth-synthesis", version = "0.13.0", optional = true }
2020
anyhow.workspace = true
2121
thiserror.workspace = true

crates/synth-backend/src/arm_backend.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,15 +433,20 @@ fn compile_wasm_to_arm(
433433
// sound (flags reused only when nothing clobbers them in the window; the
434434
// boolean deleted only when provably dead) — see `fuse_cmp_select`.
435435
//
436-
// BEHIND `SYNTH_CMP_SELECT_FUSE=1` while it is validated against the
437-
// differential oracle + gale's on-target gust_codegen_bench (G474RE). Off by
438-
// default ⇒ a literal no-op ⇒ every fixture stays bit-identical
439-
// (control_step 0x00210A55 / flat+inlined flight_algo 0x07FDF307 / divseam).
440-
// The default-on flip is the held byte-changing step, gated on silicon.
441-
let arm_instrs = if std::env::var("SYNTH_CMP_SELECT_FUSE").is_ok() {
436+
// DEFAULT-ON as of v0.13.0 (#428): cmp→select fusion ships by default. The
437+
// byte-changing flip is validated by (a) the unicorn execution oracle that runs
438+
// the two-move `mov{invert(c)}` arm (cmp_select_two_move_differential.py), (b)
439+
// gale's gale_decider_diff 10,596-case sweep across all 8 verified primitives
440+
// (native ≡ flag-off ≡ flag-on = 0x88e73178d232bcf5), and (c) the named-anchor
441+
// differentials re-run with fusion ON — control_step still 0x00210A55, flat+
442+
// inlined flight_algo still 0x07FDF307 (results preserved; bytes deliberately
443+
// changed, re-frozen on this commit). Escape hatch: `SYNTH_NO_CMP_SELECT_FUSE=1`
444+
// reverts to the pre-fusion lowering. The on-silicon G474RE DWT no-regression
445+
// check is a tracked post-ship follow-up (gale owns it).
446+
let arm_instrs = if std::env::var("SYNTH_NO_CMP_SELECT_FUSE").is_err() {
442447
// The rewritten stream is identical to `fuse_cmp_select`'s 2-tuple form;
443448
// the extra `two_move` count is diagnostic only (the fusion census /
444-
// blast-radius datum for the flip decision — #7 made that arm reachable).
449+
// blast-radius datum — #7 made that arm reachable).
445450
let (out, fused, two_move) =
446451
synth_synthesis::liveness::fuse_cmp_select_with_stats(&arm_instrs);
447452
if std::env::var("SYNTH_FUSE_STATS").is_ok() {

0 commit comments

Comments
 (0)