5.3 KiB
§135 — Six byte-verified gcc-2.7.2 idioms from the P30 S6f-h waves (and the two-lane wave shape that found them)
Distilled from ~100 agent-drafted functions gated whole-binary across three waves. Each idiom below CLOSED a specific residual — none is a hypothesis.
The codegen idioms
-
UNSIGNED switch index ⇒ pure equality chain (no range test).
switch (*(s32 *)(p+0x30))over cases {0,1,2,3} emits a balanced tree with ansltirange split;switch (*(u32 *)(p+0x30))emitsbeq 1 / beqz / beq 2 / beq 3with no comparison at all. For an unsigned index the case-0 leaf satisfiesnode_has_low_bound(0 == TYPE_MIN), soemit_case_nodesdrops the bound test. If the target's switch has no range check, read the index UNSIGNED. (func_8017C910, 92 ins.) -
ARRAY_REFvsINDIRECT_REFchanges ALIASING, therefore scheduling. Writing a field read asa0[0x46]makes it an ARRAY_REF, which setsMEM_IN_STRUCT_P; gcc-2.7.2'strue_dependence()then DROPS the dependence between an in-struct varying load and a not-in-struct constant-address store, and the load hoists. Writing the same read as*(s16 *)((s32)a0 + 0x8C)keeps it a plain INDIRECT_REF and restores the dependence. A 4-instruction "scheduling residual" that is really a type-form choice. (func_8017CFE0.) -
A constant store whose top bit is set in the STORED width needs an UNSIGNED destination.
*(u16 *)p = 0x8C00emitsori(viaforce_fit_type, the value stays positive);*(s16 *)p = 0x8C00folds to sign-extended −29696 andliemitsaddiu. If the target materializes the constant withori, the destination is unsigned. (func_8018A0F4.) -
The list scheduler PRESERVES the relative order of disambiguable stores. A store written late in source SINKS to the end of the block rather than hoisting into load-delay slots. Two field-zero stores had to be written ABOVE a three-halfword copy to land at the target's indices — 9 mismatches → 0, no permuter. When a store lands too late, move it earlier in SOURCE. (
func_8017CAB4.) -
A
shortloop counter blocks strength reduction on array indexing.for (s16 i…) p[i].f0emits a sign-extend + multiply chain; walking explicit pointers (p++,q++) reproduces the original's biv/giv set. The 1998 source walked pointers. (func_8017C738, 96 ins.) -
Frame size off by a constant ⇒ DEAD LOCALS, not a codegen bug. A draft that is structurally exact but yields a
0x40frame against the target's0x50shows everyspdisplacement off by exactly0x10— the original declared locals ahead of the live ones. Add the padding declaration. The tell is that ALL diffs aresp-relative immediates of one constant delta. (func_8017FD58.)
The integration idioms (these decide whether a byte-correct draft BANKS)
match_oneMATCH ≠ a bank. It compiles standalone and cannot see the TU's other declarations. Measured across the three waves: 83% → 93% → 71%(+reconcile to 89%) of agent MATCHes survived the whole-binary gate. Always finish on the whole-binary gate (G3/P9).- cc1 reports only the FIRST conflict, so a draft can look one edit away and hold three more. One draft had invented prototypes for six symbols the TU declares, two BELOW the splice point. grep the whole TU for every symbol the draft names, in one pass.
- An interior address has no symbol.
D_801DA0F0does not exist — it is offset0x6CintoD_801DA084. Alui/addiupair can build an INTERIOR pointer; declaring the interior address as its own extern givesundefined referenceat LINK, not a compile error. Find the containing symbol in the data.sand index into it. (func_8017C5F0.) - Never redeclare a C-library name. A draft's own
memcpyprototype collided with the TU's — which declaresmemcpythree times with incompatible signatures. (func_8018A860.)
The wave shape that produced these
Two lanes, and the reconcile lane is the reliable one (12/12 across two waves).
- Draft lane: cheap tier (Haiku ≡ Opus at ≤~50 ins, ~4.8× cheaper —
cheap-tier-ab-validated), Opus direct ≥90 ins, Opus escalation in between. 17 of wave-1's 20 banks were Haiku. - Reconcile lane: for every gate failure, the orchestrator captures the compiler error first and embeds it. Agents cannot run the gate, so without the error a declaration conflict reads to them as a codegen wall — S29's law, re-confirmed. With it: 12/12.
- Between waves, do all three: paste args from a DERIVED manifest (never typed — a hand-transcribed path list cost wave 1 three agents' time); capture blockers; and promote wave-N's Opus discoveries into wave-N+1's cheap-tier prompt. Bank rate 83% → 93% on that alone.
- Concurrency hazard: if N reconcile targets share ONE TU, FORBID agent builds — concurrent splice-builds clobber a tracked file. Allow the single permitted splice-build only when targets are spread across TUs. (Guard the campaign, not the process — §the S27 law.)
- An agent that rejects your premise is working correctly. Told a draft was byte-correct and only
declaration-blocked, one agent re-ran
match_onefirst, found a real 1-instruction DIFF, and fixed both. Hand agents the evidence, not the conclusion.