From c42b3dbc3586997a052a88101c7df4e64ced5a48 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:20:46 -0600 Subject: [PATCH] =?UTF-8?q?docs(cookbook):=20=C2=A7373=20=E2=80=94=20the?= =?UTF-8?q?=20dead-reset=20cse-breaker,=20the=20anti-dep=20pin,=20and=20pr?= =?UTF-8?q?i(asm)=3D1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the fable escalation that closed ov_SC06_010/func_8017E764 (8 -> 0, BOTH clusters), and it is three findings not one: 1. DEAD-RESET CSE-BREAKER. To stop cse merging two computations of the same expression WITHOUT an asm's scheduling footprint: name it, use it, then 'p = 0;' immediately after. cse invalidates at the second set and flow deletes the dead set BEFORE sched1 -- zero bytes, zero LUID disturbance. An empty-asm re-tie by contrast is a REAL pre-call insn whose def->asm->arg chain fronts that argument's addiu, and on this function that WAS the second residual cluster (§361 confirmed: the lever caused the bug it was later blamed on). Removing the dead-reset costs +2 ins / +8 frame bytes, so it is load-bearing. 2. A REGISTER PIN THAT DELETES A sched2 ANTI-DEP. sched1's birthing boost sinks a single-set 'la' to its consumer, local-alloc reuses the freed scratch, and sched2 is then walled by store-reads-$v0 -> la-writes-$v0. A pin on the address pointer deletes the anti-dep. Note this is where a pin is RIGHT, against §368 where pins measured worse -- the discriminator is breaking a false anti-dependence (works) vs out-arguing local-alloc about an allocation (fails). 3. HARD FACT: gcc-2.7.2 insn_cost (sched.c:1363) sets LINK_COST_FREE on any dep whose consumer is unrecognizable (INSN_CODE<0 = every inline asm), so pri(asm)=1 ALWAYS. An asm can never inherit a load's latency into its priority. That closes off a whole family of plausible levers. Also cross-referenced §370: this run was briefed to test that bound FIRST and reported it did NOT explain the residual. §370's claim is unchanged and still narrow; the transferable habit is checking whether a recorded bound covers your case before declaring a residual unreachable. --- docs/cookbook-index.md | 28 ++++++++++++++++++---- docs/matching-cookbook.md | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index a16a9aac06..9c27c19198 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 / 1023 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 / 1028 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. @@ -101,7 +101,7 @@ - **§346** — `c ? X : -X` TAKES expand_expr's COND_EXPR **SINGLETON** PATH (copy, then negate IN PLACE) — AN if/else STATEMENT GIVES THE TWO-ARM FORM (P31 S67; byte-proven ov_SC03_102/func_80180C38, closed the last instruction) L31322 - **§370** — ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/func_8001BC6C, 69 ins, NOT closed — 33 → 28 over ~45 measured compiles) L31838 -### instruction scheduling (78) +### instruction scheduling (81) - **§3-T2** — Source statement order drives instruction scheduling L78 - **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) L107 @@ -181,8 +181,11 @@ - **§352** — ⚠ TWO IDENTICAL `__asm__ __volatile__("")` BARRIERS **MERGE WITH EACH OTHER** — SPELL THE SECOND ONE DIFFERENTLY (P31 S67; byte-proven resident/func_800D128C, measured closeness 105 when they merged) L31486 - **§361** — ★ — A LOOP-TAIL BYTE SIGNATURE THAT NAMES ITS SOURCE SHAPE — AND THE LAW THAT A "SCHEDULING TIE" MAY BE YOUR OWN EARLIER LEVER (P31 S68; byte-proven main/func_800241C0, fable escalation, 19 → 0 in 3 iterations) L31637 - **§370** — ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/func_8001BC6C, 69 ins, NOT closed — 33 → 28 over ~45 measured compiles) L31838 +- **§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-2.** — A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE L31997 +- **§3-3.** — HARD FACT FOR THE SCHEDULING MAP — an `asm` ALWAYS has priority 1 L32010 -### register allocation & pins (123) +### register allocation & pins (125) - **§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 @@ -307,8 +310,10 @@ - **§347** — LOOP REGISTER ASSIGNMENT IS A **DECLARATION-ORDER + LIVE-RANGE** DIAL: FIVE COMPOSABLE LEVERS, 178 -> 0 (P31 S67; byte-proven ov_SC06_029/func_8017EF34, 243 ins) L31342 - **§365** — PIN **BOTH** MASKS OR NEITHER (P31 S68; ov_SC01_000/func_8017E594, 357 ins) L31748 - **§368** — ★★★ — THE **RELOAD-REMAT CONSTANT**: REACH A REGISTER NO PIN CAN REACH (P31 S68; ov_SC03_105/func_80187A30, 339 ins, fable escalation closed 8 → 0 in ONE edit) L31792 +- **§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-2.** — A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE L31997 -### CSE / redundancy / rematerialization (41) +### CSE / redundancy / rematerialization (43) - **§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 @@ -351,6 +356,8 @@ - **§351** — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5) L31456 - **§352** — ⚠ TWO IDENTICAL `__asm__ __volatile__("")` BARRIERS **MERGE WITH EACH OTHER** — SPELL THE SECOND ONE DIFFERENTLY (P31 S67; byte-proven resident/func_800D128C, measured closeness 105 when they merged) L31486 - **§368** — ★★★ — THE **RELOAD-REMAT CONSTANT**: REACH A REGISTER NO PIN CAN REACH (P31 S68; ov_SC03_105/func_80187A30, 339 ins, fable escalation closed 8 → 0 in ONE edit) L31792 +- **§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 ### loops & induction variables (43) @@ -1276,7 +1283,7 @@ - **§361** — ★ — A LOOP-TAIL BYTE SIGNATURE THAT NAMES ITS SOURCE SHAPE — AND THE LAW THAT A "SCHEDULING TIE" MAY BE YOUR OWN EARLIER LEVER (P31 S68; byte-proven main/func_800241C0, fable escalation, 19 → 0 in 3 iterations) L31637 - **§370** — ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/func_8001BC6C, 69 ins, NOT closed — 33 → 28 over ~45 measured compiles) L31838 -### (unbucketed — title matched no symptom vocabulary) (303) +### (unbucketed — title matched no symptom vocabulary) (304) - **§3-How** — to use this L30 - **§1** — Idiom catalog (asm pattern → C that produces it) L39 @@ -1581,6 +1588,7 @@ - **§363** — ★★ — THE OVERLAY-LAYOUT ASSUMPTION IS A SYSTEMIC BUG CLASS, AND `main` IS THE EXCEPTION THAT FINDS IT (P31 S68; six instances, four of them in one session) L31705 - **§369** — REUSE THE **COMPARE CONSTANT'S OWN VARIABLE** FOR A MASK THAT KEEPS COALESCING (P31 S68; md_SC07_004/func_801AEC38, 365 ins) L31822 - **§372** — ★★★ — THE **COPY-CAPTURE PAIR**, AND THE ONE ZERO-BYTE EDIT THAT DEFEATS BOTH (P31 S68; byte-proven main/func_8003491C, 78 ins, fable escalation closed 5 → 0) L31939 +- **CROSS-REFERENCE** — TO §370 — checked and found INAPPLICABLE here, which is the point L32018 ## All sections, in order @@ -2608,6 +2616,11 @@ - **§370** — ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/func_8001BC6C, 69 ins, NOT closed — 33 → 28 over ~45 measured compiles) L31838 - **§371** — ★★ — CARVING A **SINGLE-OBJECT MODULE BINARY**, AND THE spimdisasm RODATA-MIGRATION TRAP THAT FOLLOWS (P31 S68; byte-proven md_MAIN_003, func_800D0D6C 345 ins) L31890 - **§372** — ★★★ — THE **COPY-CAPTURE PAIR**, AND THE ONE ZERO-BYTE EDIT THAT DEFEATS BOTH (P31 S68; byte-proven main/func_8003491C, 78 ins, fable escalation closed 5 → 0) L31939 +- **§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 +- **§3-2.** — A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE L31997 +- **§3-3.** — HARD FACT FOR THE SCHEDULING MAP — an `asm` ALWAYS has priority 1 L32010 +- **CROSS-REFERENCE** — TO §370 — checked and found INAPPLICABLE here, which is the point L32018 --- @@ -3643,3 +3656,8 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: ` | L31838 | §370 | ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/fun | | L31890 | §371 | ★★ — CARVING A **SINGLE-OBJECT MODULE BINARY**, AND THE spimdisasm RODATA-MIGRATION TRAP T | | L31939 | §372 | ★★★ — THE **COPY-CAPTURE PAIR**, AND THE ONE ZERO-BYTE EDIT THAT DEFEATS BOTH (P31 S68; by | +| L31977 | §373 | ★★★ — THE **DEAD-RESET CSE-BREAKER**, THE PIN THAT BREAKS A sched2 ANTI-DEP, AND WHY AN `a | +| L31979 | §3-1. | DEAD-RESET CSE-BREAKER — the zero-footprint replacement for a §195-I asm re-tie | +| L31997 | §3-2. | A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE | +| L32010 | §3-3. | HARD FACT FOR THE SCHEDULING MAP — an `asm` ALWAYS has priority 1 | +| L32018 | CROSS-REFERENCE | TO §370 — checked and found INAPPLICABLE here, which is the point | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index cf49b8e31e..9aec548090 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -31973,3 +31973,52 @@ through reload. Here the rows are pure shift/`slti` with no commutative operands hold, and the RTL dumps named copy-capture instead. **The escalation was told to CHECK whether §368's tell applied rather than assume it, reported that it did not, and found the real cause** — which is the procedure §361 asks for, working as intended. + +## §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) + +### 1. DEAD-RESET CSE-BREAKER — the zero-footprint replacement for a §195-I asm re-tie +To stop cse merging two computations of the same address/expression (the classic case: `&local` +passed to two calls) **without** an asm's scheduling footprint: + + p = expr; /* name it */ + f(..., p); /* use it */ + p = 0; /* DEAD-RESET, immediately after */ + +cse's forward scan invalidates the equivalence at the second set, and `flow` deletes the dead set +**before sched1** — so it costs **zero bytes and zero LUID/priority disturbance**. + +**Why this beats the asm re-tie:** an empty-asm re-tie is a REAL pre-call insn whose +`def -> asm -> arg` chain has an early LUID and therefore FRONTS that argument's `addiu` over its +siblings. That is a scheduling side effect, and on this function it *was* the second residual +cluster — §361 confirmed, the lever caused the bug it was later blamed on. +Proof the dead-reset is load-bearing rather than cosmetic: removing it costs **+2 instructions and ++8 frame bytes**. + +### 2. A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE +**Symptom:** the target interleaves an address materialization (an `la` pair) between an unrelated +load and its store; yours emits load / store / `la` serially **in the same register**. +**Cause chain, in order:** sched1's birthing boost sinks the single-set `la` to its consumer → +local-alloc reuses the just-freed scratch (`$v0`) → **sched2 is then walled by the +store-reads-`$v0` → `la`-writes-`$v0` ANTI-dependence**. +**Fix:** a `register __asm__` pin on the address pointer to the TARGET's register deletes that +anti-dep, and sched2 reproduces the interleave. Pair it with splitting the deref from its `+K` +consumer around the neighbouring statement to set LUID fill order. +Note this is a case where a pin is exactly right — contrast §368, where pins were measured WORSE. +The discriminator is WHAT the pin is for: breaking a false anti-dependence (works) versus trying to +out-argue local-alloc about an allocation (fails). + +### 3. HARD FACT FOR THE SCHEDULING MAP — an `asm` ALWAYS has priority 1 +`gcc-2.7.2 insn_cost` (**sched.c:1363**) sets `LINK_COST_FREE` on any dependence whose CONSUMER is +unrecognizable — `INSN_CODE < 0`, which is **every inline asm**. So an asm can never inherit a load's +latency-2 into its priority: **`pri(asm) = 1`, always.** +**Do not try to raise an instruction's priority by feeding a load through an asm.** That closes off a +whole family of plausible-looking levers, which is why it is worth its space next to §370's +`schedule_select` bound. + +### CROSS-REFERENCE TO §370 — checked and found INAPPLICABLE here, which is the point +This escalation was briefed to test §370's bound (a ready load always beats an equal-priority ALU +leaf) against cluster 1 FIRST. It reported that the bound did **not** explain this residual — the +cause was the birthing-boost → local-alloc → anti-dep chain above — and then found the real one. +§370's claim is unchanged and still narrow: it applies to *simultaneously-ready same-priority leaves*. +The habit is the transferable part: check whether a recorded bound actually covers your case before +concluding the residual is unreachable.