mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 14:59:48 -04:00
docs(phase-31): cookbook §176d — seed the conflict table from the TU, key it per file, and cast the callee through a function pointer
The wave-J/K/L draft recovery (S52) showed §176b was under-scoped: it made batched drafts agree with each other and forgot the file they land in. Banks (a) TU-seeded conflict detection and its iterative behaviour, (b) per-destination-file keying, and (c) the new recovery variant for a callee the TU prototypes as (void) while your call must pass an argument. All 11 recovered drafts re-verified MATCH after repair; none needed a codegen change.
This commit is contained in:
+26
-24
@@ -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 / 531 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 / 532 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>L16817</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16856</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>L16817</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16881</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16856</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16920</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>L16811</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16841</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16881</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16850</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16880</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16920</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>L16907</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L16946</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>L16841</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16880</sub>
|
||||
|
||||
### types, signedness & load/store width (34)
|
||||
|
||||
@@ -408,7 +408,7 @@
|
||||
- **§171a** — THE MECHANICAL A-PROP DRAFT (P30 S50): 256 members banked with no agent in the loop <sub>L16417</sub>
|
||||
- **§171b** — THREE CARRIES THE MECHANICAL DRAFT NEEDS (P30 S50, banking the top-reach families) <sub>L16467</sub>
|
||||
|
||||
### integration / TU plumbing (40)
|
||||
### integration / TU plumbing (41)
|
||||
|
||||
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L437</sub>
|
||||
- **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) <sub>L483</sub>
|
||||
@@ -450,6 +450,7 @@
|
||||
- **§162** — THE LICM PAIR: what makes an address a movable AT ALL, and why the preheader order is the body order (P30 S47, `ov_MAIN_012`) <sub>L11140</sub>
|
||||
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
|
||||
- **§173** — THE STORED-PLUMBING RECOVERY RECIPE (P31 T6): symfix-first, per-group isolation, and where the verdicts have no drafts <sub>L16603</sub>
|
||||
- **§176d** — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15) <sub>L16800</sub>
|
||||
|
||||
### build graph, splat & the harness (110)
|
||||
|
||||
@@ -562,7 +563,7 @@
|
||||
- **§165** — S48 WAVE-4 HARVEST (P30, 2026-08-12): banked the same day the wave landed <sub>L13686</sub>
|
||||
- **§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>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16800</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16839</sub>
|
||||
|
||||
### process, measurement & doctrine (75)
|
||||
|
||||
@@ -639,8 +640,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>L16881</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L16933</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16920</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L16972</sub>
|
||||
|
||||
### (unbucketed — title matched no symptom vocabulary) (177)
|
||||
|
||||
@@ -819,8 +820,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>L16955</sub>
|
||||
- **What** — is NOT banked here <sub>L16972</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L16994</sub>
|
||||
- **What** — is NOT banked here <sub>L17011</sub>
|
||||
|
||||
|
||||
## All sections, in order
|
||||
@@ -1347,12 +1348,13 @@
|
||||
- **§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>
|
||||
- **§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>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16800</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16811</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16817</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16841</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16881</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L16907</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L16933</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L16955</sub>
|
||||
- **What** — is NOT banked here <sub>L16972</sub>
|
||||
- **§176d** — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15) <sub>L16800</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L16839</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L16850</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L16856</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L16880</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L16920</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L16946</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L16972</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L16994</sub>
|
||||
- **What** — is NOT banked here <sub>L17011</sub>
|
||||
|
||||
@@ -16797,6 +16797,45 @@ compile standalone, so N drafts bring N independent `extern` sets into one TU:
|
||||
costs a full clean rebuild per step (a 41-draft bisect ran 28 minutes producing nothing) while the
|
||||
compiler had already printed the symbol and line. Read the error first.
|
||||
|
||||
## §176d — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15)
|
||||
|
||||
§176b's batch rule was right but **under-scoped**: it made drafts agree with *each other* and
|
||||
forgot the file they land in. Recovering the 11 conflict-dropped main drafts from waves J/K/L
|
||||
exposed both halves of the mistake, and the second one is the expensive one.
|
||||
|
||||
**(a) Seed the symbol table from the DESTINATION TU, not from nothing.** A draft can contradict a
|
||||
declaration that is *already in the .c* — put there by a function banked three waves ago. Draft-vs-
|
||||
draft comparison is blind to it, so the contradiction sails past the checker and surfaces only as a
|
||||
compile error plus a bisect. Real case: `src/800.c` has carried `extern void func_8001C9D0(void);`
|
||||
since `func_8001C2C4` banked, while three wave-J drafts declared the same callee `(s32)` and
|
||||
`(void *)`. On the 11-draft recovery slate the TU-seeded check named **7 real conflicts the old
|
||||
check missed entirely** — and it found them *iteratively*: fixing one draft reveals the next
|
||||
clash behind it, so re-run the dry run until it reports `N -> N compatible, 0 dropped`.
|
||||
|
||||
**(b) Key the table PER DESTINATION FILE.** A single slate-wide namespace makes two drafts landing
|
||||
in *different* `.c` files illegally "conflict" over a symbol they are each entitled to declare
|
||||
their own way. Separate TUs are separate namespaces (R39: over-refusal silently discards good work,
|
||||
which is worse than letting a failure through to the gate that would catch it).
|
||||
|
||||
**The recovery lever, extended — cast the CALLEE through a function pointer.** §176b/§174-Law-4
|
||||
covers adopting the TU's declaration for *data* and for *your own* parameters. The case they don't
|
||||
cover: the TU prototypes a callee as taking **no argument** while your function must pass one. You
|
||||
cannot pass an argument to a `(void)` prototype, and you must not change the TU's declaration
|
||||
(other banked functions depend on it). Cast the function itself at the call site:
|
||||
|
||||
```c
|
||||
extern void func_8001C9D0(void); /* the TU's declaration, verbatim */
|
||||
...
|
||||
((void (*)(s32))func_8001C9D0)(a0); /* the call the target actually makes */
|
||||
```
|
||||
|
||||
gcc-2.7.2 emits the identical `jal` with `$a0` set — a direct call to a named symbol is unaffected
|
||||
by the cast. **All 11 recovered drafts re-verified MATCH after repair**, across every variant used:
|
||||
this function-pointer cast (×3), a pointer-type cast on an argument (`(unsigned long *)`), signed↔
|
||||
unsigned data re-declaration (`u16`/`s8`, ×3), and array↔scalar (`extern u8 D_x;` + `(u32)&D_x`, ×3).
|
||||
Zero of the eleven needed a codegen change — **every one of them was a plumbing repair**, which is
|
||||
the standing P31 finding (`matching-is-solved-integration-is-the-bottleneck`) showing up once more.
|
||||
|
||||
## §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
|
||||
|
||||
Reference in New Issue
Block a user