Skip to content

Commit cc203ec

Browse files
avrabeclaude
andauthored
feat(vcr-ra): ship immediate-shift folding default-on — v0.15.0 (#390, #242) (#467)
Flips the immediate-shift folding peephole default-on (PR #463 landed it flag-off). A constant shift amount the stack selector materialized into a scratch register (`movw rM,#C; lsl rD,rN,rM`) now folds to the immediate form (`lsl rD,rN,#C`), removing the dead `movw` — −1 instruction, −1 live register per folded shift. Flip: arm_backend.rs default-ON with opt-out SYNTH_NO_IMM_SHIFT_FOLD=1. Re-froze the ARM goldens (control_step 316→304, flight_seam 866→774, flight_seam_flat 1006→910 = −200 B; signed_div_const unchanged — no register-shift folds). RV32 gate untouched (ARM-only peephole). Results preserved across the byte change: control_step 0x00210A55 (differential 13/13), flat+inlined flight_algo 0x07FDF307 (MATCH); opt-out restores the v0.14.0 bytes; full workspace suite green. Validated bit-identical + a net cycle win on the dissolved hot path (−2 cyc/call, .text 100→90 B on gust_mix). Cumulative dissolved hot-path: 64.0 → 58.0 (cmp→select) → 50.0 (local promotion) → 48.0 cyc/call. Pin-swept 0.14.0→0.15.0; CHANGELOG added. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6ae1e7b commit cc203ec

15 files changed

Lines changed: 86 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.15.0] - 2026-06-24
11+
12+
**Immediate-shift folding is now DEFAULT-ON (VCR-RA, #390, epic #242).** The stack
13+
selector lowers `i32.shl/shr_s/shr_u` to register-shift forms, materializing a
14+
constant shift amount into a scratch register (`movw rM,#C; lsl rD,rN,rM`); the
15+
peephole now folds that to the immediate form (`lsl rD,rN,#C`) and removes the dead
16+
`movw` — −1 instruction and −1 live register per folded shift. This is a
17+
**byte-changing** release on top of v0.14.0: `.text` shrinks on shift-heavy
18+
functions — control_step 316→304 B, flight_seam 866→774, flight_seam_flat 1006→910
19+
(−200 B across the frozen fixtures); signed_div_const (no register-shift folds)
20+
unchanged.
21+
22+
Execution results are unchanged: control_step `0x00210A55` (differential 13/13) and
23+
flat+inlined flight_algo `0x07FDF307` are preserved. Validated bit-identical and a
24+
net cycle win on the dissolved hot path (−2 cyc/call, `.text` 100→90 B on gust_mix).
25+
Cumulative dissolved hot-path improvement across the codegen levers:
26+
64.0 → 58.0 (cmp→select) → 50.0 (local promotion) → 48.0 cyc/call.
27+
28+
Soundness: only folds shift amounts in [1,31] (where register- and immediate-shift
29+
forms provably agree), the shift-amount register must be dead after the shift, and
30+
the rewrite is removal-only (offset-neutral before branch resolution). Escape hatch:
31+
`SYNTH_NO_IMM_SHIFT_FOLD=1` restores the register-shift form.
32+
1033
## [0.14.0] - 2026-06-24
1134

1235
**i32 local promotion is now DEFAULT-ON (VCR-RA-001, #390, epic #242).** The ARM

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.14.0"
30+
version = "0.15.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.14.0",
10+
version = "0.15.0",
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.14.0" }
14+
synth-core = { path = "../synth-core", version = "0.15.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.14.0" }
15-
synth-synthesis = { path = "../synth-synthesis", version = "0.14.0" }
14+
synth-core = { path = "../synth-core", version = "0.15.0" }
15+
synth-synthesis = { path = "../synth-synthesis", version = "0.15.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.14.0" }
14+
synth-core = { path = "../synth-core", version = "0.15.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.14.0" }
19-
synth-synthesis = { path = "../synth-synthesis", version = "0.14.0", optional = true }
18+
synth-core = { path = "../synth-core", version = "0.15.0" }
19+
synth-synthesis = { path = "../synth-synthesis", version = "0.15.0", optional = true }
2020
anyhow.workspace = true
2121
thiserror.workspace = true

crates/synth-backend/src/arm_backend.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,11 +492,10 @@ fn compile_wasm_to_arm(
492492
// stack selector materialized into a scratch register (`movw rM,#C; lsl rD,rN,rM`)
493493
// folds to the immediate form (`lsl rD,rN,#C`), removing the dead `movw` — −1
494494
// instruction, −1 live register. Removal-only (offset-neutral before branch
495-
// resolution, like the dead-store pass). BEHIND `SYNTH_IMM_SHIFT_FOLD=1`
496-
// (opt-in, off by default ⇒ bit-identical) while it earns the execution
497-
// differential + gale's G474RE DWT gate — the same gated path local promotion
498-
// and cmp→select took before shipping default-on. gale-named lever toward ≤1.3×.
499-
let arm_instrs = if std::env::var("SYNTH_IMM_SHIFT_FOLD").is_ok() {
495+
// resolution, like the dead-store pass). DEFAULT-ON as of v0.15.0: validated
496+
// bit-identical results + a net cycle win on the dissolved hot path (−2
497+
// cyc/call, .text 100→90 B on gust_mix). Escape hatch: `SYNTH_NO_IMM_SHIFT_FOLD=1`.
498+
let arm_instrs = if std::env::var("SYNTH_NO_IMM_SHIFT_FOLD").is_err() {
500499
let (out, folds) = synth_synthesis::liveness::fold_immediate_shifts(&arm_instrs);
501500
if std::env::var("SYNTH_FUSE_STATS").is_ok() {
502501
eprintln!(

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.14.0" }
31-
synth-frontend = { path = "../synth-frontend", version = "0.14.0" }
32-
synth-synthesis = { path = "../synth-synthesis", version = "0.14.0" }
33-
synth-backend = { path = "../synth-backend", version = "0.14.0" }
30+
synth-core = { path = "../synth-core", version = "0.15.0" }
31+
synth-frontend = { path = "../synth-frontend", version = "0.15.0" }
32+
synth-synthesis = { path = "../synth-synthesis", version = "0.15.0" }
33+
synth-backend = { path = "../synth-backend", version = "0.15.0" }
3434

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

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

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

0 commit comments

Comments
 (0)