docs(phase-30 S40): cookbook §144 (literal spelling = immediate encoding) + wave-metrics S40-1 (8/8 after recovery, 0 codegen walls)

This commit is contained in:
Drew T
2026-08-05 11:15:15 -06:00
parent 64ad8a1c7a
commit 84d1193f21
3 changed files with 84 additions and 2 deletions
+4 -2
View File
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
> `docs/matching-cookbook.md` is ~716 KB / 405 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
> `docs/matching-cookbook.md` is ~716 KB / 406 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -548,7 +548,7 @@
- **§3-The** — measurement (do this before any wave; it is ~20 lines and needs no builds) <sub>L9780</sub>
- **§3-And** — the report-vs-bytes lesson attached to it <sub>L9812</sub>
### (unbucketed — title matched no symptom vocabulary) (117)
### (unbucketed — title matched no symptom vocabulary) (118)
- **§3-How** — to use this <sub>L30</sub>
- **§1** — Idiom catalog (asm pattern → C that produces it) <sub>L39</sub>
@@ -667,6 +667,7 @@
- **§3-Two** — wrong mechanisms I chased first, and why they were wrong <sub>L9710</sub>
- **§3-The** — trap that hid it — SAME FUNCTION, TWO ROUTES, ONLY ONE IS FREE <sub>L9795</sub>
- **Route** — selection (why `--addr` sometimes says "nothing changed") <sub>L9804</sub>
- **§144** — THE LITERAL'S SPELLING PICKS THE IMMEDIATE ENCODING (P30 S40 wave 1, `func_801822E0`) <sub>L9878</sub>
## All sections, in order
@@ -1076,3 +1077,4 @@
- **Route** — selection (why `--addr` sometimes says "nothing changed") <sub>L9804</sub>
- **§3-And** — the report-vs-bytes lesson attached to it <sub>L9812</sub>
- **§143** — `cast_call_sites` read a RETURN STATEMENT as a prototype and deleted it. A 0/39 sweep became 18/39. (P30 S40) <sub>L9824</sub>
- **§144** — THE LITERAL'S SPELLING PICKS THE IMMEDIATE ENCODING (P30 S40 wave 1, `func_801822E0`) <sub>L9878</sub>
+39
View File
@@ -9872,3 +9872,42 @@ touched every member — and read the per-member payload before believing any wa
**Symptom lines for the index:** **"parse error before `extern'"** · **"a sweep banked 0 of N"** ·
**"a draft lost its return statement"** · **"declaration after statement in a block"**.
---
## §144 — THE LITERAL'S SPELLING PICKS THE IMMEDIATE ENCODING (P30 S40 wave 1, `func_801822E0`)
A new, byte-proven gcc-2.7.2 idiom, found by a wave agent on an 85-ins exemplar.
A byte counter stored through an `sb` was diffing on **one instruction's immediate field only**:
target : addiu $v0, $v1, 0xFF (imm 0x00FF)
ours : addiu $v0, $v1, -1 (imm 0xFFFF)
Both are *arithmetically identical modulo 256* — only the low byte survives the `sb` — and both
compile to a **single `addiu`**, same instruction count, same registers, same schedule. The compiler
is not choosing between them on any semantic ground: **it takes the immediate from how the literal
was SPELLED in the source.**
cnt = cnt - 1; -> addiu $v0,$v1,-1 (0xFFFF)
cnt = cnt + 0xff; -> addiu $v0,$v1,0xFF (0x00FF) <- matches
Signedness of the counter (`s8` vs `u8`) was tested and makes **no** difference; the spelling is the
whole lever.
**When to reach for it:** your diff is a single instruction, the mnemonic and both registers agree,
and only the **immediate field** differs — *and* the two immediates are congruent modulo the width of
the store that consumes the value (`sb` → mod 256, `sh` → mod 65536). Then re-spell the literal to the
form whose bit-pattern you need. Do NOT reach for pins, scheduling barriers or the permuter: nothing
about register allocation or ordering is wrong.
**Why it is easy to misread as intrinsic:** the residual is one immediate in one instruction, which
looks exactly like the tail of a regalloc/scheduling wall. It is not — it is a pure source-text lever,
and it is free.
**Generalisation to test when it next appears** (not yet byte-proven, so treat as a hypothesis):
the same should hold for any masked-then-truncated arithmetic where two literals are congruent modulo
the consuming store width — e.g. `x - 2` vs `x + 0xfe`, or `h - 1` vs `h + 0xffff` ahead of an `sh`.
**Symptom lines for the index:** **"only the immediate field differs"** · **"addiu -1 vs 0xFF"** ·
**"one instruction off, same registers"**.
+41
View File
@@ -152,3 +152,44 @@ fixed path — a real match reported as nothing.
**Any row in this table is a coverage claim.** Before recording one, confirm the gate accounted for
every draft (`banked + failed + no-verdict == drafts`, now asserted in `.run/s6f_gate.py`). Full
post-mortem: cookbook **§139**.
---
## Wave S40-1 (2026-08-05) — 8 targets, the first wave ever aimed at the open-only h_norm clusters
**Pool verified BEFORE the wave (R14).** The frontier report's cluster pool was carried with an
explicit "not verified" caveat, and its *other* headline claim (the whale open in 4 SC07 overlays)
had already proved 3/4 wrong. Measured from the sigs instead:
| | clusters | fns | ins | multiplier |
|---|---:|---:|---:|---:|
| claimed | 1,689 | 5,956 | 326,261 | 2.7× |
| **measured** | **1,677** | **5,795** | **319,755** | **3.68×** |
Within 2–4% on size, and the multiplier is **better** than claimed. Verify each claim separately: the
same document was right here and wrong about the whale.
**Result — and the two numbers say different things.**
| stage | result |
|---|---|
| `match_one` close=0 | **8 / 8** |
| whole-binary gate, first pass | **5 / 8** |
| after deterministic recovery | **8 / 8** — ~0 agent tokens |
**All three first-pass failures were integration plumbing, each a different known lever, ZERO codegen
walls:**
| fn | gate error | lever |
|---|---|---|
| `func_801802EC` | `redefinition of morph_lerp` | strip the **§77 probe layer** — the draft carried types + a `static inline` helper so `match_one` could compile standalone; the real TU already defines them. Scaffolding is not part of the bank. |
| `func_8018B238` | `conflicting types for D_80115158` | `recover_giant` — the draft declared it file-scope as a struct array while the TU declares `u8[]` **block-scope** inside other functions; block-scoping the draft's externs removes the collision. |
| `func_8017EF54` | `conflicting types for func_8017EF54` | **§37/§124 def-side asm-label alias** — TU declares `void f(void)` for no-arg callers, byte-true def takes `s32` in `$a0`; no-prototype escape illegal once a param promotes, so the definition takes a private C identifier + `__asm__("func_8017EF54")`. |
**The lesson for reading any future wave row: the gate number is not the close-rate.** 5/8 measured
integration, not matching. Run the recovery ladder before recording a wave's yield, or the table will
under-report the drafters and send the next wave hunting compiler walls that are not there.
**Cost:** 1.31M subagent tokens, 8 agents, 0 errors. **Idioms harvested:** cookbook §144 (literal
spelling picks the immediate encoding). **Defect found:** `.run/ghidra_c/func_8017EF54.c` is a stale
decompile of the WRONG function — the prefetch cache is not trustworthy per-entry.