mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-29 23:24:32 -04:00
docs(cookbook): §428a — the fence<->over-merge coupling (agent-measured, flagged not-yet-byte-proven)
A volatile __asm__ barrier is a scheduling AND allocation event, so on a function whose residual is allocation-shaped every fence that kills the double-hop re-enables a cross-jump over-merge. Two residuals in tension, which is why ~20 variants across two attempts never converged. §428's UID-based barrier is the predicted resolution because it changes no liveness; the escalation now running is the test. Flagged explicitly as one agent's report, not a byte-proof (R14).
This commit is contained in:
+11
-5
@@ -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 / 1096 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 / 1097 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,7 +34,7 @@
|
||||
## By symptom
|
||||
|
||||
|
||||
### delay slots & branches (66)
|
||||
### delay slots & branches (67)
|
||||
|
||||
- **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch <sub>L90</sub>
|
||||
- **§5a** — Cross-jump tail-merge — gcc collapses two byte-identical blocks the original kept separate (FIX FOUND) <sub>L211</sub>
|
||||
@@ -102,8 +102,9 @@
|
||||
- **§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) <sub>L31838</sub>
|
||||
- **§396g** — ★★ — A GUARD LADDER'S RUNGS MUST STAY SYMMETRIC OR `reorg.c` LOSES ITS BRANCH REDIRECT (P31 S69; byte-proven ov_SC03_028/func_80184C90, 92 ins) <sub>L32818</sub>
|
||||
- **§428** — ★★★ — A ZERO-BYTE CROSS-JUMP BARRIER: ADVANCE THE POINTER INSIDE EACH SWITCH ARM (P31 S72; `main/func_80026D64`, 218 ins, MATCH in 2 compiles) <sub>L33950</sub>
|
||||
- **§428a** — ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven) <sub>L33988</sub>
|
||||
|
||||
### instruction scheduling (88)
|
||||
### instruction scheduling (89)
|
||||
|
||||
- **§3-T2** — Source statement order drives instruction scheduling <sub>L78</sub>
|
||||
- **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) <sub>L107</sub>
|
||||
@@ -193,8 +194,9 @@
|
||||
- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) <sub>L33108</sub>
|
||||
- **§424** — ★★★ — EQUAL-PRIORITY STORES COME OUT **REVERSED**: sched1's LUID tie picks the LAST statement first (P31 S71; byte-proven `ov_SC07_006/func_801890FC`, 387 ins) <sub>L33807</sub>
|
||||
- **§428** — ★★★ — A ZERO-BYTE CROSS-JUMP BARRIER: ADVANCE THE POINTER INSIDE EACH SWITCH ARM (P31 S72; `main/func_80026D64`, 218 ins, MATCH in 2 compiles) <sub>L33950</sub>
|
||||
- **§428a** — ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven) <sub>L33988</sub>
|
||||
|
||||
### register allocation & pins (131)
|
||||
### register allocation & pins (132)
|
||||
|
||||
- **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) <sub>L854</sub>
|
||||
- **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register <sub>L875</sub>
|
||||
@@ -327,6 +329,7 @@
|
||||
- **§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) <sub>L33353</sub>
|
||||
- **§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) <sub>L33605</sub>
|
||||
- **§419** — ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte-proven `ov_SC01_000/func_8017DD04`, 297 ins) <sub>L33658</sub>
|
||||
- **§428a** — ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven) <sub>L33988</sub>
|
||||
|
||||
### CSE / redundancy / rematerialization (45)
|
||||
|
||||
@@ -1223,7 +1226,7 @@
|
||||
- **§426** — ★★★ — main's SWITCH FUNCTIONS WERE NEVER A CODEGEN WALL: ONE RODATA CARVE HAD BEEN MISSING SINCE PHASE 7 (P31 S72; 3 of the 11 "PROVEN gate-rejects" banked byte-identical in 14 s) <sub>L33855</sub>
|
||||
- **§427** — ★★ — A HASH IS A CORRECTNESS ORACLE WITH ZERO DIAGNOSTIC CONTENT; PRESERVE THE RED ARTIFACT BEFORE ANYTHING REBUILDS OVER IT (P31 S72) <sub>L33931</sub>
|
||||
|
||||
### process, measurement & doctrine (132)
|
||||
### process, measurement & doctrine (133)
|
||||
|
||||
- **§8e** — The jtbl ALIGNMENT LAW + the pad-spec filter — multi-table .rodata spans (Phase 29, byte-proven; `.run/probe_jtbl/verdict.md`) <sub>L549</sub>
|
||||
- **§3-The** — mechanism: game-code dedup is SOURCE-LEVEL, not an object swap (R-D1, the key lesson) <sub>L945</sub>
|
||||
@@ -1357,6 +1360,7 @@
|
||||
- **§3-E.** — WHAT THE AGENTS REFUTED <sub>L33148</sub>
|
||||
- **§408** — ★★★ — §406 REFUTED AS A SWEEP: THE SHAPE IS THE FAMILY, THE DISAGREEMENT IS THE DEFECT (P31 S71; 0 MATCH / 14 applied, 0 / 210) <sub>L33209</sub>
|
||||
- **§411** — ★★★ — THE PACK MUST CARRY THAT FUNCTION'S OWN HISTORY (P31 S71; measured 38/39 vs 124/131) <sub>L33386</sub>
|
||||
- **§428a** — ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven) <sub>L33988</sub>
|
||||
|
||||
### (unbucketed — title matched no symptom vocabulary) (325)
|
||||
|
||||
@@ -2785,6 +2789,7 @@
|
||||
- **§426** — ★★★ — main's SWITCH FUNCTIONS WERE NEVER A CODEGEN WALL: ONE RODATA CARVE HAD BEEN MISSING SINCE PHASE 7 (P31 S72; 3 of the 11 "PROVEN gate-rejects" banked byte-identical in 14 s) <sub>L33855</sub>
|
||||
- **§427** — ★★ — A HASH IS A CORRECTNESS ORACLE WITH ZERO DIAGNOSTIC CONTENT; PRESERVE THE RED ARTIFACT BEFORE ANYTHING REBUILDS OVER IT (P31 S72) <sub>L33931</sub>
|
||||
- **§428** — ★★★ — A ZERO-BYTE CROSS-JUMP BARRIER: ADVANCE THE POINTER INSIDE EACH SWITCH ARM (P31 S72; `main/func_80026D64`, 218 ins, MATCH in 2 compiles) <sub>L33950</sub>
|
||||
- **§428a** — ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven) <sub>L33988</sub>
|
||||
|
||||
|
||||
---
|
||||
@@ -3893,3 +3898,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
|
||||
| L33855 | §426 | ★★★ — main's SWITCH FUNCTIONS WERE NEVER A CODEGEN WALL: ONE RODATA CARVE HAD BEEN MISSING |
|
||||
| L33931 | §427 | ★★ — A HASH IS A CORRECTNESS ORACLE WITH ZERO DIAGNOSTIC CONTENT; PRESERVE THE RED ARTIFAC |
|
||||
| L33950 | §428 | ★★★ — A ZERO-BYTE CROSS-JUMP BARRIER: ADVANCE THE POINTER INSIDE EACH SWITCH ARM (P31 S72; |
|
||||
| L33988 | §428a | ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN ( |
|
||||
|
||||
@@ -33984,3 +33984,33 @@ optimizer cannot look up.
|
||||
byte-identical against `jtbl_80072BFC`, plus 6 `jal` relocs at their exact offsets and 11
|
||||
`D_800A5E60` hi/lo pairs, before calling it done. **That verification happened because the pack
|
||||
carried the §426 carve note telling it to.** Journal fuel earned its keep here.
|
||||
|
||||
## §428a ★★ — THE FENCE↔OVER-MERGE COUPLING: WHY A CROSS-JUMP BARRIER CAN COST YOU A REGALLOC WIN (P31 S72, `main/func_8001B0D4`; AGENT-MEASURED, not yet byte-proven)
|
||||
|
||||
**Status flag first (R14):** this is one agent's report over 12+ A/Bs at closeness 53 with length
|
||||
EXACT (86/86) and the jtbl structure byte-verified. It is a strong observation, not a byte-proof, and
|
||||
the §428 resolution below is a PREDICTION under test — do not cite it as settled.
|
||||
|
||||
**The observation.** On a function whose residual is a gcc-2.7.2 regalloc **double-hop**
|
||||
(`$2 → $a0 → $v1`) inside two nested switch dispatchers, every lever that reliably kills the
|
||||
double-hop — scoping, inline-assign, goto-shared-tail, and **§5a `volatile __asm__` cross-jump
|
||||
barriers** — re-enables a **2-instruction cross-jump OVER-merge** elsewhere (case 0's own
|
||||
`D_800747E4` reload folds into the shared tail). The two residuals are in direct tension: each fence
|
||||
that fixes one re-creates the other, which is why ~20 variants across two attempts all landed at a
|
||||
similar closeness instead of converging.
|
||||
|
||||
**Why this is a class, not a one-off.** A `volatile __asm__` barrier is a scheduling AND allocation
|
||||
event, not just a cross-jump one: it forces values live across the barrier and changes the merge
|
||||
depth of every tail that reaches it. So "add a fence" is never a local edit on a function whose
|
||||
remaining residual is allocation-shaped — it moves both variables at once, and a two-variable search
|
||||
driven one fence at a time does not converge.
|
||||
|
||||
**The predicted resolution — §428.** Use the barrier that is NOT a fence: advance the cursor inside
|
||||
each switch arm so the converging insn becomes a `cross_jump`-created label with
|
||||
`INSN_UID >= max_uid`, which shuts off `jump.c:1988`'s minimum=2 search with **zero bytes and no
|
||||
liveness change**. That removes the over-merge half without touching allocation, leaving the
|
||||
double-hop lever free to act alone. **If you are reading this and the escalation landed, promote this
|
||||
section to byte-proven and say which lever finally moved `$v1`.**
|
||||
|
||||
**The general habit:** when two residuals move in opposite directions under every lever you try, stop
|
||||
searching and ask which lever changes only ONE of them.
|
||||
|
||||
Reference in New Issue
Block a user