docs(phase-31): cookbook §176f — the declaration FORM is a matching lever; reconcile toward the form the match needs (S52)

Wave O: six drafts in one TU referenced D_80078D88, three declaring it scalar and three as an
array. One draft's own comment explained why the array form is load-bearing: with a scalar decl the
global load is a plain symbol_ref and sched1 HOISTS the lui/lw above a store; declaring it as an
array makes gcc-2.7.2 alias.c treat the access as possibly-aliasing and the hoist stops.

So §176b/§176d's 'pick one form and cast at the use site' is wrong for a scalar/array clash. Array
is the STRONGER form -- scalar users adopt it for free by indexing [0] (byte-verified on all three)
-- while forcing an array user to scalar can re-enable the hoist and break the match. Reconciling
toward the array form took the slate from 42 -> 37 compatible (5 dropped) to 42/42, every converted
draft re-verified MATCH. Waves J/K/L each lost 5-10 drafts to the greedy keep-first rule.
This commit is contained in:
Drew T
2026-08-15 11:16:43 -06:00
parent 965ae3902e
commit 279037ece6
2 changed files with 57 additions and 24 deletions
+26 -24
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 / 533 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 / 534 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.
@@ -42,7 +42,7 @@
- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED <sub>L10065</sub>
- **§162** — CROSS-JUMP DIRECTION: the surviving copy is always the LATER one, so a BACKWARD `j` into a sibling arm is a source `goto` (P30 S48) <sub>L11263</sub>
- **§162** — The cross-jump "CALL veto" is a COUNT law, not a CALL law (BOUNDS §88a; P30 S48, `func_80189540`) <sub>L11299</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16913</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16944</sub>
### instruction scheduling (22)
@@ -66,8 +66,8 @@
- **§3-A.** — `move_movables` hoists iff `threshold × savings × lifetime ≥ insn_count` — and you can read it <sub>L10148</sub>
- **§16Z** — SHARPENS *(sharpens §37 "the /s-DEP LATTICE", §136-13, §136-14, §16Xy, §162q, `gcc-2.7.2-map/sched.md` §64)* <sub>L14337</sub>
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16913</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16977</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16944</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17008</sub>
### register allocation & pins (46)
@@ -114,16 +114,16 @@
- **Bonus** — facts worth keeping <sub>L10754</sub>
- **§156** — THE PREFERENCE-DONOR MERGE: cross-region variable reuse is what fills a0-a3, and a call-arg use in ONE region steers the fill in ALL of them (P30 S46 tier-3, `func_80186E24`, 611 ins: 236-off "S11 regalloc-order" → MATCH, zero new pins) <sub>L10769</sub>
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16907</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16937</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16977</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16938</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16968</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17008</sub>
### CSE / redundancy / rematerialization (4)
- **§46** — The `func_80178D40` crack (890 ins ×134, the heaviest core in the game): four LOOP-STRUCTURE levers cheap-Opus found by reading loop.c/jump.c/cse.c (Phase 26 session 8, 2026-07-13) <sub>L3313</sub>
- **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom <sub>L6452</sub>
- **§153** — THE ADDRESS-REMATERIALISATION LAUNDER: a third zero-emission asm lever (P30 S43, `func_8018D98C`, 710 ins) <sub>L10463</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17003</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17034</sub>
### loops & induction variables (10)
@@ -175,7 +175,7 @@
- **§3-The** — `/s` drop clause is in ALL THREE dependence predicates, so the FIXED-ADDRESS STORE is what floats (P30 S48, `func_8017CA18`, ov_MAIN_012) <sub>L12299</sub>
- **§16Z** — SHARPENS *(sharpens §37 "the /s-DEP LATTICE", §136-13, §136-14, §16Xy, §162q, `gcc-2.7.2-map/sched.md` §64)* <sub>L14337</sub>
- **§3-The** — ADDRESS-CLASS TABLE: which load/store pairs even REACH the `/s` clause (P30 S48 wave 4, `func_80185B44`, ov_SC03_014) <sub>L14339</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16937</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16968</sub>
### types, signedness & load/store width (34)
@@ -214,7 +214,7 @@
- **§3-C.** — PAC type 1 = the same payload class as type 4, just NOT compressed <sub>L10545</sub>
- **§155b** — check the TYPE your oracle returns before comparing against it (S45 p5) <sub>L10584</sub>
### declarations, prototypes & K&R (57)
### declarations, prototypes & K&R (58)
- **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch <sub>L90</sub>
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L437</sub>
@@ -273,6 +273,7 @@
- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED <sub>L10065</sub>
- **§159** — THE DECLARATION AXIS: conform to byte-truth, and make every guard state its COVERAGE (P30 S47; ~10,930 sites across 8 axes, fleet byte-identical) <sub>L10825</sub>
- **§168** — THE COUSIN TIER (P30 S49, 2026-08-12): h_seq's exact-hash brittleness, measured — and the similarity map above it <sub>L16208</sub>
- **§176f** — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52) <sub>L16896</sub>
### jump tables & switches (27)
@@ -564,7 +565,7 @@
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
- **§167** — S48 WAVE-5/6 HARVEST (P30, 2026-08-12): the saturation point <sub>L14955</sub>
- **§176e** — SYMBOL IDENTITY IS COMPUTABLE OFFLINE (P31 S52): `tools/reloc_identity.py` <sub>L16839</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16896</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16927</sub>
### process, measurement & doctrine (75)
@@ -641,8 +642,8 @@
- **§165z** — REFUTED THIS WAVE: do NOT re-derive <sub>L14855</sub>
- **§167z** — REFUTED IN WAVES 5/6: do NOT re-derive <sub>L16151</sub>
- **§168** — THE COUSIN TIER (P30 S49, 2026-08-12): h_seq's exact-hash brittleness, measured — and the similarity map above it <sub>L16208</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16977</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17029</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17008</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17060</sub>
### (unbucketed — title matched no symptom vocabulary) (177)
@@ -821,8 +822,8 @@
- **§174** — THE ADAPT-CARD WAVE RECIPE (P31 waves A/B, 2026-08-14): prevention beats recovery <sub>L16639</sub>
- **§176a** — THE VERIFICATION-LAYER LAWS (P31 overnight, 2026-08-15). What each check can and cannot prove. <sub>L16734</sub>
- **§176b** — BATCH-GATING MECHANICS (P31): what changes when N drafts land in ONE .c <sub>L16774</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17051</sub>
- **What** — is NOT banked here <sub>L17068</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17082</sub>
- **What** — is NOT banked here <sub>L17099</sub>
## All sections, in order
@@ -1351,12 +1352,13 @@
- **§176b** — BATCH-GATING MECHANICS (P31): what changes when N drafts land in ONE .c <sub>L16774</sub>
- **§176d** — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15) <sub>L16800</sub>
- **§176e** — SYMBOL IDENTITY IS COMPUTABLE OFFLINE (P31 S52): `tools/reloc_identity.py` <sub>L16839</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16896</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16907</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16913</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16937</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16977</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17003</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17029</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17051</sub>
- **What** — is NOT banked here <sub>L17068</sub>
- **§176f** — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52) <sub>L16896</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16927</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16938</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16944</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16968</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17008</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17034</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17060</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17082</sub>
- **What** — is NOT banked here <sub>L17099</sub>
+31
View File
@@ -16893,6 +16893,37 @@ The probe was still worth it — the reloc filter was a genuinely new discrimina
the A10 rate?" was unanswered — but the *prior* should have been ~8%, not the optimistic read I
started with.
## §176f — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52)
§176b/§176d treat an in-TU declaration conflict as *plumbing*: pick one form, cast at the use site,
move on. Wave O found the case where that advice is actively wrong.
Six drafts in one TU referenced `D_80078D88`. Three declared it `extern s32 D_80078D88;`, three
`extern s32 D_80078D88[];` — and one of those drafts carried a comment explaining exactly why:
> with `extern s32 D_80078D88;` the global load is a plain scalar at a `symbol_ref`, so **sched1
> hoisted the `lui/lw` above the `pkt->uv3` store**; declaring it as an ARRAY makes gcc-2.7.2's
> `alias.c` treat the access as possibly-aliasing and the hoist stops.
**So the declaration form is load-bearing codegen, not style.** Resolve such a conflict by asking
which form the MATCHES need, then converting the other drafts toward it:
- array is the *stronger* form — it constrains gcc more, so scalar users can adopt it for free by
indexing `D_x[0]` (identical bytes: verified on all three here);
- the reverse is NOT free — forcing an array user to scalar can re-enable the hoist and break it.
Result: **42/42 drafts compatible, 0 dropped**, where the greedy keep-first rule would have dropped
5. Every one re-verified MATCH after conversion. Wave J/K/L each lost 5–10 drafts to this rule, and
those were logged as "recoverable with cast-at-use" — for a *scalar/array* clash the right repair is
usually not a cast at all, it is **converting the whole TU to the array form**.
**Procedure (do this before every batch gate):**
1. dry-run the gate; for each conflict, grep which drafts declare which form and *why*;
2. reconcile toward the form the matches need (array > scalar; the TU's own decl wins over both);
3. re-verify EVERY converted draft with `match_one` — the conversion is a codegen change, so it is
only free if the bytes say so;
4. re-run the dry run until it reports `N -> N compatible, 0 dropped`.
## §176c — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY
main's `make extract` runs the EXE-only `psyq_integrate` + `ld_interleave` steps, which **rewrite the