diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index 9e2d0f19b..6698b659b 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -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 / 412 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 / 419 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. @@ -34,13 +34,14 @@ ## By symptom -### delay slots & branches (3) +### delay slots & branches (4) - **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch L90 - **§5a** — Cross-jump tail-merge — gcc collapses two byte-identical blocks the original kept separate (FIX FOUND) L211 - **§3-D.** — THE CROSS-JUMP RATCHET (the sharpest new trap — `func_80131340` L-C) L3501 +- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058 -### instruction scheduling (15) +### instruction scheduling (16) - **§3-T2** — Source statement order drives instruction scheduling L78 - **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) L107 @@ -57,8 +58,9 @@ - **§66d-5** — `residual_class`'s "structural ⇒ permuter CPU is waste" is WRONG for schedule permutations (measured, Phase 29 SESSION-18) L5484 - **§3-The** — attribution primitive (use this before calling anything a scheduling residual) L6050 - **§3-The** — scheduling rules (refining §135-2 and §135-4) L8902 +- **Consequence** — for the family (a real scheduling decision) L10085 -### register allocation & pins (33) +### register allocation & pins (35) - **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) L835 - **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register L856 @@ -93,6 +95,8 @@ - **§3-Two** — further notes worth keeping L8241 - **§137** — REGALLOC-PERM is a TWO-COMPILE ARITHMETIC PROBLEM, not a permuter job L9334 - **§3-The** — same swallow, twice more, in the integration spine L9699 +- **§3-B.** — A `?:` on MEMORY operands costs ~16 bytes of invisible frame; on REGISTER operands, zero L10047 +- **§3-D.** — A lone `$t8`/`$t9` in the target is RELOAD SCRATCH — reproduce the spill, don't pin the register L10063 ### CSE / redundancy / rematerialization (2) @@ -177,7 +181,7 @@ - **§143** — `cast_call_sites` read a RETURN STATEMENT as a prototype and deleted it. A 0/39 sweep became 18/39. (P30 S40) L9824 - **Then** — propagation returned 0/137 TWICE — both times a missing TYPE L9990 -### declarations, prototypes & K&R (54) +### declarations, prototypes & K&R (55) - **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch L90 - **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) L437 @@ -233,6 +237,7 @@ - **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is L9555 - **§141** — The §134 class is CLOSED: every line-shape decision now routes through `cdecl._mask` (P30 S39) L9730 - **§143** — `cast_call_sites` read a RETURN STATEMENT as a prototype and deleted it. A 0/39 sweep became 18/39. (P30 S40) L9824 +- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058 ### jump tables & switches (26) @@ -278,7 +283,7 @@ - **§127a** — §71 (sibling-first) is the strongest `-O0` lever, and it beats the index L8370 - **§132** — The `JR-PAIR-IN-ONE-O0-OBJECT` "wall" was TWO instrument defects: a merged-double span the carve could not see, and a truncated object no rule deleted (P30 S29, `func_8013B83C` + `func_8013BD74`) L8563 -### family propagation & sweeps (71) +### family propagation & sweeps (74) - **§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) L483 - **§11** — Cross-binary dedup & code-sharing (Phase 11 — "one match unlocks many") L908 @@ -351,6 +356,9 @@ - **§142** — An open stub whose `h_exact` class is MATCHED elsewhere is FREE. Propagate the body; do not gate a draft. (P30 S39, +7,710 ins in two commands) L9768 - **§143** — `cast_call_sites` read a RETURN STATEMENT as a prototype and deleted it. A 0/39 sweep became 18/39. (P30 S40) L9824 - **Then** — propagation returned 0/137 TWICE — both times a missing TYPE L9990 +- **§3-A.** — The frame has THREE strata, and stratum 3 is unreachable from C L10031 +- **§3-E.** — A `qty_compare` TIE is not spelling-reachable — recognise it and stop L10073 +- **Consequence** — for the family (a real scheduling decision) L10085 ### integration / TU plumbing (36) @@ -493,7 +501,7 @@ - **§142** — An open stub whose `h_exact` class is MATCHED elsewhere is FREE. Propagate the body; do not gate a draft. (P30 S39, +7,710 ins in two commands) L9768 - **§3-The** — measurement (do this before any wave; it is ~20 lines and needs no builds) L9780 -### process, measurement & doctrine (57) +### process, measurement & doctrine (59) - **§8e** — The jtbl ALIGNMENT LAW + the pad-spec filter — multi-table .rodata spans (Phase 29, byte-proven; `.run/probe_jtbl/verdict.md`) L530 - **§3-The** — mechanism: game-code dedup is SOURCE-LEVEL, not an object swap (R-D1, the key lesson) L926 @@ -552,6 +560,8 @@ - **§3-The** — measurement (do this before any wave; it is ~20 lines and needs no builds) L9780 - **§3-And** — the report-vs-bytes lesson attached to it L9812 - **§146** — RE-MEASURE A WALL BEFORE YOU RESPECT IT. Both "permanent" giants fell to drafts already on disk. (P30 S6, +50,094 ins) L9967 +- **§147** — The three-stratum FRAME LAW, and four "stop searching" verdicts (P30 S42, `func_8017C294`, serial run) L10026 +- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058 ### (unbucketed — title matched no symptom vocabulary) (120) @@ -1091,3 +1101,10 @@ - **Then** — propagation returned 0/137 TWICE — both times a missing TYPE L9990 - **§3-Two** — errors of mine, both instructive L9999 - **§3-The** — rule L10013 +- **§147** — The three-stratum FRAME LAW, and four "stop searching" verdicts (P30 S42, `func_8017C294`, serial run) L10026 +- **§3-A.** — The frame has THREE strata, and stratum 3 is unreachable from C L10031 +- **§3-B.** — A `?:` on MEMORY operands costs ~16 bytes of invisible frame; on REGISTER operands, zero L10047 +- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058 +- **§3-D.** — A lone `$t8`/`$t9` in the target is RELOAD SCRATCH — reproduce the spill, don't pin the register L10063 +- **§3-E.** — A `qty_compare` TIE is not spelling-reachable — recognise it and stop L10073 +- **Consequence** — for the family (a real scheduling decision) L10085 diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 7a8ac8042..1bed34c4f 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -10020,3 +10020,75 @@ is repaired, the verdicts it produced become **hypotheses again**, not facts. **Symptom lines for the index:** **"a documented wall"** · **"an old close= verdict"** · **"match_one MATCH but the whole binary differs"** · **"a sweep returns 0 of N twice"**. + +--- + +## §147 — The three-stratum FRAME LAW, and four "stop searching" verdicts (P30 S42, `func_8017C294`, serial run) + +Five levers from one serial crack. It did **not** bank (NEAR 12/246, zero structural divergence, and +`permuter_ils` plateaus at exactly 12) — but the knowledge transfers, which is why the run was serial. + +### A. The frame has THREE strata, and stratum 3 is unreachable from C + +gcc-2.7.2 lays out the frame in order: **(1)** declared locals, in declaration order, ascending from +the outgoing-args top · **(2)** reload spill slots · **(3)** a trailing block the function's `?:` +chains allocate and **never reference**. §136-6 ("slots assigned in DECLARATION order") describes only +stratum 1. + +**Symptom → verdict:** *if the target's mystery slot sits at the TOP of the frame, adjacent to the +saved-register area, it is stratum 3 — and NO declaration-order, filler-array, `volatile`, or +inner-block edit can reach it.* Stop looking for the missing local. + +**Measurement recipe (30 seconds, deterministic):** delete the min/max tail, recompile, re-read +`.frame … # vars=`. **The drop IS stratum 3's size.** (Here: exactly 96 bytes.) Run this BEFORE +drafting anything large with a min/max tail — it converts an unbounded "which local am I missing?" +hunt into a yes/no. + +### B. A `?:` on MEMORY operands costs ~16 bytes of invisible frame; on REGISTER operands, zero + + minx = MIN(outp[0][0], outp[1][0]); /* memory operands -> +16 bytes of frame */ + a = outp[0][0]; b = outp[1][0]; minx = a 0 bytes */ + +They are **not** interchangeable. The memory form is also what emits the target's `lhu`+`lh` +double-read of one stack slot (the frame-size counterpart to §136-9). **So when a draft's frame is a +multiple of 16 too large around a min/max chain, COUNT THE `?:`s before inventing a dead local** +(§83c's trap, seen from the other side). Corollary proven here: a zero-temp tail is unreachable when +the target re-reads its operands — 219 ins (if/else) and 234 ins (operands bound to locals) vs 246. + +### C. Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED + +`expand_function_start` walks the whole `BLOCK` tree, so `{ … T x; … }` lands at the same stratum-1 +offset as a function-scope declaration. **Do not spend a cycle on it.** + +### D. A lone `$t8`/`$t9` in the target is RELOAD SCRATCH — reproduce the spill, don't pin the register + +MIPS defines no `REG_ALLOC_ORDER` (regalloc.md K3), so plain allocation never reaches `$24`/`$25` +unless everything below is busy. An inherited draft here pinned `register short *dst2 __asm__("$24")` +to force `lw $t8`; the pin then pushed `mfhi` off `$t8` onto `$t9` — **a diff the pin itself created.** +The correct lever was structural: delete the `volatile` "out" local and let the `a1` parameter spill +naturally — reload picks `$t8` for both store and reload for free, and `mfhi $t8` comes right too. +**Generalises §17/§72: before pinning a high register, check whether the target's value is a SPILL and +reproduce the spill instead.** + +### E. A `qty_compare` TIE is not spelling-reachable — recognise it and stop + +`QTY_CMP_PRI = log2(nrefs)·nrefs·size / (death − birth)`. When two quantities have equal ref counts +and live ranges differing by one insn, the register grant flips with statement order and **both +orders cost the same**. Here `(mw; xw; mh; yh)` buys the target's emission order and `mh → $a0` but +transposes `w/h`; `(mw; mh; xw; yh)` buys the registers and loses the order — both exactly 5. + +**Tell:** structure exactly right, exactly ONE register PAIR transposed, and the alternative ordering +transposes a DIFFERENT pair. Swept here: 72 statement permutations × 4 declaration orders × 7 +s16/s32 retypings × `?:`-MAX spellings × ref-count shifts × `$v0/$v1` pins, plus the permuter — floor +unchanged in every direction. **Worth ~an hour to recognise early.** + +### Consequence for the family (a real scheduling decision) + +The blocker is a **frame-layout fact about the body**, not a per-overlay symbol thing, so all 15 +siblings will hit it identically: the same draft remapped reaches 12/246 on each and **none will +bank**. **Do not spend the 15 until stratum 3 is explained.** When it closes, `family_remap` carries +all 16 in one pass. + +**Symptom lines for the index:** **"a mystery stack slot at the top of the frame"** · **"frame is a +multiple of 16 too large"** · **"a lone $t8/$t9 in the target"** · **"exactly one register pair +transposed"** · **"permuter and hand-search plateau at the same number"**.