1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! #390 / VCR-PERF-001 — tracked size oracle for the gust hot path.
//!
//! gale measured synth v0.11.50 lowering the gust mini-RTOS scheduler hot path
//! at ~3.9x the code size of native rustc/LLVM (gust_poll 816 B vs 208 B;
//! gust_mix 44 B vs 12 B). The gap is almost entirely synth-side lowering. The
//! companion harness `scripts/repro/size_attribution_390.py` attributes synth's
//! OWN measured `.text` into named causal buckets (spill/reload, addressing-mode
//! folding misses, redundant const, prologue/shadow-stack, guard/bool, copy) —
//! the map the perf lanes (VCR-RA-001 et al.) follow. The attribution report is
//! `artifacts/size_attribution_390.md`.
//!
//! This test is the *gate*: it pins the exact per-function `.text` size of the
//! gust fixture on the DEFAULT (optimized) path — the path #390's numbers
//! describe. A size regression reddens CI; a size WIN reddens it too and forces
//! a deliberate pin update (the pin going DOWN is the visible evidence a perf
//! lane landed). The fuzzy bucket attribution deliberately does NOT enter this
//! gate — instruction->cause is a judgement call owned by the report, exact
//! bytes are the machine-checkable fact.
//!
//! Method: per-function size = delta between sorted `.text` symbol addresses
//! (next symbol / section end) — the same symtab the frozen-fixture
//! differentials read; `st_size` is not relied upon. Identical to the helper in
//! `shift_mask_elide_686.rs`.
use BTreeMap;
use Command;
use ;
/// Compile gust_kernel on the DEFAULT optimized path (no `--relocatable`) and
/// return per-function `.text` sizes by symbol name (sorted-address deltas).
/// Locked per-function `.text` sizes (bytes), default optimized path, synth
/// v0.39.1. Numbers are MEASURED (see `artifacts/size_attribution_390.md`).
/// gust_poll/gust_mix are gale's #390 benchmark functions; func_0 is the kiln
/// `transition` body, func_1 the internal `mix`. To repin after a deliberate
/// size change, run the test and copy the printed REPIN block.
///
/// REPINNED (#390 spill-reduction, v0.42 lane): gust_poll 740 → 724 (−16 B by
/// this oracle's symbol-delta method; machine code is 722 + 2 B alignment
/// pad, −18) — `forward_stack_reloads` upgraded to a
/// conditional-branch-transparent holder-lattice walk (19 reloads forwarded /
/// deleted across gust_poll's br_if compare→branch ladders). Correctness
/// evidence on the new bytes BEFORE this repin: the full
/// scripts/repro/*_differential.py sweep incl. the new
/// gust_spill_fwd_390_differential.py (gust_poll state+return vs wasmtime in
/// default + both lever opt-outs).
///
/// REPINNED (#390 spill-reduction, v0.44 Lane D): gust_poll 724 → 716 (−8 B by
/// this oracle's symbol-delta method; machine code 722 → 716, −6, one redundant
/// `str.w r0,[sp,#40]` + 2 B realignment) — `forward_stack_reloads` extended
/// with REDUNDANT-STORE elimination: a `str rd,[sp,#N]` whose slot `#N` the
/// holder lattice PROVES already holds `rd`'s value (a caller-save re-spilled
/// unchanged between two calls) writes bytes the slot already has and is
/// deleted. Same `#606` frozen-span guard as reload-deletion (a deletion inside
/// a resolved branch→target span would shift the pre-resolved displacement); on
/// deletion the holder set is left UNCHANGED (the slot content is unaltered, so
/// every co-holder stays valid). Correctness evidence on the new bytes BEFORE
/// this repin: full scripts/repro/*_differential.py sweep (90 PASS; the 6
/// failures — 5 fact_spec require `--features verify`, 1 u64_unpack_riscv a
/// pre-existing RISC-V unicorn harness issue — fail IDENTICALLY on the pristine
/// origin/main binary), incl. gust_spill_fwd_390_differential.py (gust_poll
/// return + post-call state struct vs wasmtime in default + both lever
/// opt-outs). Only gust_poll's bytes changed; func_0/func_1/gust_mix identical.
// RE-PINNED for the #846 SYNTH_SHIFT_MASK_ELIDE default-on flip (v0.50.0): the
// scheduler's pin/shift bit-arithmetic drops the redundant #682 mod-32 re-mask,
// shrinking gust_poll 716→692 (−24), func_0 408→380 (−28), func_1 76→60 (−16);
// gust_mix (no register shifts) is unchanged. Execution UNCHANGED — re-pinned
// only after gust_spill_fwd_390_differential.py PASSED on the new default-on
// bytes (gust_poll return + post-call state struct vs wasmtime).
// RE-PINNED for the #872 range-realloc cross-barrier soundness fix (v0.53):
// gust_poll 692→696 (+4). This is a SOUNDNESS COST, deliberately paid. The pass
// no longer treats a segment live-in as dead at its last IN-SEGMENT use, so a
// register holding a value post-segment code may still read is no longer a
// recolouring target. gust_poll carries the exact #869 shape the issue reported:
// base: movw r3, #0 mvns r5, r3 <- writes pass-through r3
// now: movw r5, #0 mvns r5, r5 <- r3's exit value preserved
// The +4 is the knock-on colouring change in the udiv/mls block downstream (one
// const materialization the tighter colouring leaves un-DCE'd, `lsl.w`→`lsls`
// recovering 2 B of it). func_0/func_1/gust_mix are byte-IDENTICAL.
// Execution UNCHANGED — re-pinned only after gust_spill_fwd_390_differential.py
// PASSED on the new bytes (gust_poll return + post-call state struct vs
// wasmtime, in default and both lever opt-outs), alongside the full
// trap-semantics oracle set and the #494 bounds differential.
const LOCKED: & = &;