diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index c08faa2aad..080055aff7 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 / 1084 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 / 1085 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. @@ -191,7 +191,7 @@ - **§393** — ★★ — THE **BIRTHING BOOST**: A SINGLE-SET LOCAL IS SCHEDULED LAST; GIVE IT A SECOND SET (P31 S69; byte-proven ov_SC02_017/func_8017FCFC) L32543 - **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) L33108 -### register allocation & pins (129) +### register allocation & pins (130) - **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) L854 - **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register L875 @@ -322,8 +322,9 @@ - **§375** — AN `$a0`-`$a3` PIN USED LATE RELOCATES AN **EARLIER** OUTGOING-CALL USE OF THAT REGISTER (P31 S68; main/func_8005F0C8, 88 ins) L32042 - **§3-C.** — REGISTER ALLOCATION FROM C, WITHOUT PINS L33124 - **§410** — ★★★ — COPY THEN ACCUMULATE ON THE COPY: resolving the birthing-boost vs register-allocation dilemma (P31 S71; byte-proven `ov_SC04_015/func_8017EB78`, 98 ins) L33353 +- **§417** — ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `cse` SKIP-BLOCKS MERGE (P31 S71; byte-proven `ov_SC03_013/func_8017E6F4`, 182 ins) L33605 -### CSE / redundancy / rematerialization (44) +### CSE / redundancy / rematerialization (45) - **§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) L3347 - **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom L6486 @@ -369,6 +370,7 @@ - **§373** — ★★★ — THE **DEAD-RESET CSE-BREAKER**, THE PIN THAT BREAKS A sched2 ANTI-DEP, AND WHY AN `asm` CAN NEVER RAISE PRIORITY (P31 S68; byte-proven ov_SC06_010/func_8017E764, 438 ins, fable escalation closed 8 → 0) L31977 - **§3-1.** — DEAD-RESET CSE-BREAKER — the zero-footprint replacement for a §195-I asm re-tie L31979 - **§385** — ★★★ — THE **SCHED2 PRIORITY-DONOR ASM**: closing the "hoisted-invariant vs IV-init preheader swap" class (P31 S69; byte-proven main/func_80038A58, 347 ins, fable escalation 2 → 0) L32309 +- **§417** — ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `cse` SKIP-BLOCKS MERGE (P31 S71; byte-proven `ov_SC03_013/func_8017E6F4`, 182 ins) L33605 ### loops & induction variables (46) @@ -2754,6 +2756,7 @@ - **§414** — ★★★ — `parallel_gate` ON `main` IS A FALSE PASS, AND THE RULE WAS ALREADY WRITTEN DOWN (P31 S71) L33510 - **§415** — ★★ — A FILE-SCOPE DECL MAKES gcc-2.7.2 MERGE THE TU'S LATER *BLOCK-SCOPE* EXTERNS INTO IT (P31 S71; byte-proven `ov_SC04_011/func_80180B24`, 215 ins) L33547 - **§416** — ★★ — FOUR LEVERS FROM THE S71 OVERNIGHT LANE, none of which the cookbook held (P31 S71) L33572 +- **§417** — ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `cse` SKIP-BLOCKS MERGE (P31 S71; byte-proven `ov_SC03_013/func_8017E6F4`, 182 ins) L33605 --- @@ -3850,3 +3853,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: ` | L33510 | §414 | ★★★ — `parallel_gate` ON `main` IS A FALSE PASS, AND THE RULE WAS ALREADY WRITTEN DOWN (P3 | | L33547 | §415 | ★★ — A FILE-SCOPE DECL MAKES gcc-2.7.2 MERGE THE TU'S LATER *BLOCK-SCOPE* EXTERNS INTO IT | | L33572 | §416 | ★★ — FOUR LEVERS FROM THE S71 OVERNIGHT LANE, none of which the cookbook held (P31 S71) | +| L33605 | §417 | ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `c | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 6d1579c56e..10b7c8a1e1 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -33601,3 +33601,30 @@ the width cost two instructions per COMPARE, here it changes the LOAD itself.) `ov_SC06_000` (an unrelated 11-ins function), on `ov_SC01_080` (two different functions), and on `ov_SC03_030`. In every case the real fuel was a **same-TU neighbour** (§194-E). The address-twin lead is worth checking and never worth trusting — law 1c exists for this. + +## §417 ★★★ — A REGISTER PIN CAN BLOCK `jump.c`'s SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A `cse` SKIP-BLOCKS MERGE (P31 S71; byte-proven `ov_SC03_013/func_8017E6F4`, 182 ins) + +**Two compiler passes in a chain, and the first agent misattributed the second to the first.** The +prior attempt sat at a 3-instruction residual with a `$3` pin on a select's result and concluded that +"unpinning costs +2". Both halves were wrong in an instructive way. + +**1. The pin blocked `jump.c`.** A PINNED select arm expands as `ior` + a copy — TWO insns — so +`jump.c:728`'s `x = b; if (c) x = a;` collapse cannot fire, and reorg emits `bne`/`ori`/`move`. +Removing the pin lets the collapse happen. **A hard-register pin is not neutral to the RTL +optimisers: it changes the INSN COUNT of the pattern they pattern-match on.** + +**2. Unpinning then exposed a different pass.** With every select collapsed, `cse`'s +`cse_end_of_basic_block` **skip_blocks** path now walks from the first `D_80184D2C[idx]` read all the +way to the second and CSEs the `symbol_ref` into `$s3` — the +2 the earlier agent blamed on the +unpinning. The residual moved; it did not grow. + +**The fix is to end the cse block, not to restore the pin:** put a REAL diamond between the two uses +(a `vol` clamp written as `if`/`else`, whose IOR arm is uncollapsible), keep `register vol +__asm__("$5")` so both arms land in `$a1`, and spell the absolute value as +`if ((s16)w < 0) w = -w; e = w;`. Four compiles from there. + +**The general law.** *When removing a lever moves the residual instead of shrinking it, the new +residual is a DIFFERENT PASS — attribute it before re-adding the lever.* "Removing X costs +2" is +almost always "removing X unblocked pass A, and pass B now fires"; re-adding X re-blocks A and hides +B again, which is how a function plateaus for three attempts. The instrument is the pass dump +(`-dL`, `-dj`, `-dS`), not another guess.