mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-05 00:47:54 -04:00
docs(phase-24): T7 harvest — §35 (ranking law + banking recipe + loop idioms); 3 residuals -> backlog
- cookbook §35: the region-a sibling-giant harvest. RANKING LAW (difficulty = global-array hoisting, NOT $s-reg count — param/buffer giants one-shot Opus even at all-8-$s); the ×134 banking recipe (fix_arity_callers --any-proto -> sig_unify -> strip/anonymize local typedefs -> harvest_verify -> dedup_propagate; skip cast_call_sites on no-proto); new loop idioms (dest-off-base giv, index-form source, sltiu/slti-without-CSE, div2 range-extension). - 3 deferred residuals logged to docs/backlog.md (Fable5 batch fuel): func_801392FC close=2, func_8013A530 close=10, func_8013AF20 close=15 — each single-class, ×134, seed in .run/t7/. - CURRENT_PHASE: T7 harvest complete (4 giants ×134 banked, 3 deferred); next decision = Fable5 batch.
This commit is contained in:
+2942
-2951
File diff suppressed because it is too large
Load Diff
@@ -2161,3 +2161,19 @@ The 2nd region-a giant (159 ins, bit-unpack/tilemap; 2 giant-local data bases, c
|
||||
**gdb-on-cc1 (the method that settled it):** the shipped `tools/bin/gcc-2.7.2-psx/cc1` is i386-static WITH symbols — breakpoint `find_free_reg`/`post_mark_life` (`.run/t7/fable/gdbtrace.gdb`) to dump the real qty order + register grants when hand-modeling stalls. Cite the vanilla **`tools/reference/gcc-2.7.2/`** tree (now complete — global.c/local-alloc.c/reload1.c/toplev.c/function.c/flow.c/… from the FSF tarball; sched.c/loop.c/mips.c verified byte-identical to vanilla). **Pass order** (why upstream fixes reach the prologue): sched1 → local_alloc → global_alloc/reload → prologue threading (`toplev.c:3103`) → **sched2** (:3117) → jump2 → dbr; prologue saves are sched2-scheduled, everything upstream tunes sched2's LUID tie-breaks.
|
||||
|
||||
**Gotcha:** parallel `match_one` runs on the SAME function share `.run/match/<fn>` — pass a unique `--work` dir or the scores are garbage.
|
||||
|
||||
## §35 — The region-a sibling-giant harvest: difficulty ≠ $s-reg count (it's global-array hoisting) + the banking recipe + new loop idioms (Phase 24 T7, 5 parallel Opus-Max agents)
|
||||
Cracking the 5 remaining region-a giants via parallel Opus agents applying §32/§34 surfaced a **ranking law** + a reusable banking recipe.
|
||||
|
||||
**THE RANKING LAW (retires the "8-$s-reg = hardest" heuristic):** a giant's difficulty is set by **whether it hoists GLOBAL base ARRAYS into callee-saved regs**, NOT by $s-reg count. gcc-2.7.2 has no cross-bb CSE, so a hoisted *global* base can only come from a source-local pointer in the exact `lui` order (§32#1) — the genuinely hard part, needing Fable5 for the last-mile regalloc. Giants whose $s pressure is **param / local / output-buffer** derived (even all 8 $s0–$s7 live) **one-shot with Opus alone** (density-order first-fit). Byte-proven: `func_8012D098` (189, all-8-$s) + `func_8012EC04` (178, sibling+GTE-tail) MATCHED one-shot; the 3 residual monsters stall only on tiny (2–15) compiler-internal walls, not the $s allocation. **Triage a giant by its `%hi data bases`, not its $s count.**
|
||||
|
||||
**THE BANKING RECIPE (matched giant draft → ×134; per-giant integration is mechanical, §30a):**
|
||||
1. `fix_arity_callers --apply --any-proto --from-file <fn> --drafts <dir>` — no-proto the caller extern conflicting with the matched def-sig (the DEF-side wall: a shared macro in engine_core.h, or a sibling in the overlay, forward-declares the giant with a different sig → `conflicting types`). Byte-neutral (the call's arg bits are unchanged).
|
||||
2. `sig_unify` — canonicalize the giant's own CALLEE externs (no-proto `void f()` → the fleet's full proto; else args promote differently standalone vs whole-binary).
|
||||
3. **Strip draft-local typedefs already in `engine_types.h`** (a redundant `typedef …Blk16;` = `conflicting types` in the shared TU) and **anonymize named local typedefs** (`typedef {…} Buf; Buf b;` → `struct {…} b;`, else it collides with a sibling's `Buf`).
|
||||
4. `harvest_verify --chunk 1` → ×1, then `dedup_propagate --addr <A> --recover` → ×134.
|
||||
**Do NOT run `cast_call_sites` on these** — it mis-casts a no-proto `void f()` to `void(*)(void)` (0 params) and breaks the call (fix candidate: treat `()` as compatible-with-any).
|
||||
|
||||
**New loop idioms (byte-verified; §31/loop.md fodder):** *dest-off-base giv* — write every primitive store `*(u16*)((s32)p + k)` off ONE biv so they combine into a single dest-addr giv (kills giv-split); *index-form source* `param_3[j+k]` with `j+=2` (not a walked pointer) reduces to one address biv; *sltiu-outer/slti-inner without CSE* — a redundant SIGNED range-guard that must stay `slt`/`slti` needs a **separate signed-int copy** (`int s = u;`), since only CSE-*reuse* canonicalizes signed→unsigned; *div2 range-extension* — a zero-byte `asm("":: "r"(x))` after the last flag-test extends a pinned reg's live range so a trailing `andi` lands in the target reg.
|
||||
|
||||
**The 3 deferred residuals (Fable5 batch — close=2/10/15; precise root-cause in `.run/t7/<fn>.c` headers + `docs/backlog.md`):** `func_801392FC` (**2**: combine folds `(s16)`load → atomic `lh` before sched2, so the pipelineable split-load never exists; permuter can't reach) · `func_8013A530` (**10**: RC-6 reload-pressure — an `iVar7→$v1` pin over-reserves $v1 so the clamp's 2nd split reloads into $a0; directed permuter over the clamp OR Fable5) · `func_8013AF20` (**15**: loop-invariant constant-hoist ORDER — the two AND-masks materialize opposite, coupled to the AND-operand order; permuter plateaued at 15). All single-class, high byte-weight (×134), ideal Fable5 targets.
|
||||
|
||||
@@ -36,7 +36,7 @@ Whole-binary byte-gate (`tools/harvest_verify.py`) is the SOLE arbiter (G3/P9).
|
||||
|
||||
## Progress log
|
||||
*(append one line per task on completion — the crash-recovery trail)*
|
||||
- **T7 (resumed, Drew's choice) — sibling-giant harvest via parallel Opus-Max agents (2026-07-03, IN PROGRESS):** launched 5 Opus agents (one per remaining region-a giant), each applying §32/§34, escalating to Fable5 only on stall. **KEY FINDING (answers the flywheel Q):** the "3 hardest 8-$s-reg giants" were MIS-RANKED — the 8-$s pressure is param/local/buffer-derived, NOT global-array hoists (only global-array-hoisting giants like func_80129CF8 are genuinely hard), so they **one-shot with Opus alone, no Fable5**. Banked ×134 so far: **func_8012D098** (189, one-shot Opus) + **func_8012EC04** (178, one-shot Opus = sibling func_8012EA90 + GTE tail). Fleet 65.56→**65.64%** (uncommitted, clean-verify running). 3 still iterating: func_8013AF20 (~60), func_8013A530 (~45), func_801392FC. **BANKING RECIPE (established; per-giant integration is mechanical, §30a):** matched draft → `fix_arity_callers --apply --any-proto` (no-proto the engine_core.h/overlay caller extern that conflicts with the matched def-sig — the DEF-side wall) → `sig_unify` (callee no-proto→full-proto) → **strip draft-local typedefs already in engine_types.h + anonymize named local typedefs** (else `conflicting types` in the shared TU) → `harvest_verify --chunk 1` ×1 → `dedup_propagate --recover` ×134. **NOTE: skip `cast_call_sites`** — it mis-casts a no-proto `void f()` to `void(*)(void)` (T6/cookbook fix candidate). **Two-pass verdict (Drew's Q):** Opus-first is right (structure cheap + flywheel; Fable5 only for genuine global-hoist/regalloc walls); parallel Opus is fine, sequence any Fable5 escalations with idiom-banking.
|
||||
- **T7 (resumed, Drew's choice) — sibling-giant harvest via parallel Opus-Max agents (2026-07-03, IN PROGRESS):** launched 5 Opus agents (one per remaining region-a giant), each applying §32/§34, escalating to Fable5 only on stall. **KEY FINDING (answers the flywheel Q):** the "3 hardest 8-$s-reg giants" were MIS-RANKED — the 8-$s pressure is param/local/buffer-derived, NOT global-array hoists (only global-array-hoisting giants like func_80129CF8 are genuinely hard), so they **one-shot with Opus alone, no Fable5**. Banked ×134 so far: **func_8012D098** (189, one-shot Opus) + **func_8012EC04** (178, one-shot Opus = sibling func_8012EA90 + GTE tail). Fleet 65.56→**65.64%** (uncommitted, clean-verify running). 3 still iterating: func_8013AF20 (~60), func_8013A530 (~45), func_801392FC. **BANKING RECIPE (established; per-giant integration is mechanical, §30a):** matched draft → `fix_arity_callers --apply --any-proto` (no-proto the engine_core.h/overlay caller extern that conflicts with the matched def-sig — the DEF-side wall) → `sig_unify` (callee no-proto→full-proto) → **strip draft-local typedefs already in engine_types.h + anonymize named local typedefs** (else `conflicting types` in the shared TU) → `harvest_verify --chunk 1` ×1 → `dedup_propagate --recover` ×134. **NOTE: skip `cast_call_sites`** — it mis-casts a no-proto `void f()` to `void(*)(void)` (T6/cookbook fix candidate). **Two-pass verdict (Drew's Q):** Opus-first is right (structure cheap + flywheel; Fable5 only for genuine global-hoist/regalloc walls); parallel Opus is fine, sequence any Fable5 escalations with idiom-banking. **HARVEST COMPLETE (5 giants processed):** **4 banked ×134** (func_80129CF8, func_80138ED0 earlier; **func_8012D098 + func_8012EC04 this batch**, `commit:0457`, clean 136/136, fleet **65.64%**). **3 deferred to a Fable5 batch** — all Opus-driven to a single-class compiler-internal wall: `func_801392FC` **close=2** (count-load pipelining / combine-fold-vs-sched2), `func_8013A530` **close=10** (RC-6 reload-pressure, register-only, contained), `func_8013AF20` **close=15** (loop-invariant constant-hoist order). Residuals in `docs/backlog.md` + cookbook **§35** + `.run/t7/<fn>.c` headers. **RANKING LAW (retires "8-$s=hardest"):** difficulty = global-array-hoisting, NOT $s count (param/buffer giants one-shot Opus even at all-8-$s; only global-hoisters need Fable5). **BANKING RECIPE** (§35): fix_arity_callers --any-proto → sig_unify → strip engine_types.h-dup + anonymize local typedefs → harvest_verify → dedup_propagate; NOT cast_call_sites (mis-casts no-proto). **NEXT DECISION (Drew):** Fable5-batch the 3 residuals now (~1.3M tok, ~4.5h, each ×134) vs a fresh focused session vs permuter-first on the contained func_8013A530.
|
||||
- **T7b/T5 — 2nd giant `func_80138ED0` MATCHED + banked ×134; the real un-reconciled-sibling proof + major new §31 idioms (2026-07-03):** Opus applying §32 → **close=21** (159/159 ins; semantics/control-flow/constants exact; found the transferable **giv-init fence** lever) → stalled on pure regalloc/sched. **Fable5Max reading the vanilla gcc-2.7.2 source → MATCH** (every class C-reachable, no permuter). Headline finds (→ cookbook §34, byte-verified + gdb-on-cc1): **gcc-2.7.2's 3-qty local-alloc SORT BUG** (`local-alloc.c:1441` — ≤3 qtys allocate in creation not density order; fixed via a zero-instruction **decoy qty**) + the **zero-byte asm allocation toolkit** (input-only / multi-input / def+use dummies = ref-count / lifetime / sort-path dials that emit nothing, byte-gate-certified). **Banked via the standard pipeline** (validates it on a real giant): `cast_call_sites` reconciled `func_8013914C` `(u8*,u16*)`→canonical `(s32,s32)`+call-site cast; **`reconcile_decls` a NO-OP** (the 2 data bases are giant-local → no fleet conflict — confirms the tool's no-op correctness / no false-positive); `harvest_verify` ×1 (`d19c9580`) → `dedup_propagate --recover` **×134** (134 byte-identical; pins/asm body propagates fine; `func_800599B8`'s lone `(s32,s32)` decl is in `ov_SC01_077.c`, a separate TU from the `_a.c` bank → no per-member conflict). gcc-2.7.2 reference tree **completed** (18 .c). Distilled: cookbook **§34** + SETUP §5.6. **Clean fleet verify running.** T5 satisfied: tool proven on 2 real giants (func_80129CF8 reconcile-path byte-proof + func_80138ED0 no-op + full-pipeline + 2nd giant ×134). **NEXT: T6 finalize** (fold §34 into the §31 map files) **+ PhaseEnd.** Commit: (pending verify).
|
||||
- **T7b/T2+T3 — `tools/reconcile_decls.py` built + BYTE-PROVEN (2026-07-03, `commit:0453` tool + docs commit):** the DATA-symbol analog of `cast_call_sites` (§20). **Oracle** (T2): fleet-majority canonical-type picker — `engine_core.h`-macro type authoritative, else plurality across all overlays+resident (deterministic); reuses `gen_harvest_targets.collect_data_decls`; **8/8 correct** on func_80129CF8's symbols (`--print-canon`). **Transform** (T3): byte-neutral access-cast taxonomy — array `(Ed*)D_x`, struct-base `(Ed*)&D_x`, scalar-signedness `*(Td*)&D_x`, ptr-in-scalar `(*(P**)&D_x)`; ONE single-pass `re.sub` per symbol (a first draft double-wrapped the ptr-store — fixed). Wired into `gate_stage` after `cast_call_sites` (idempotent / no-op without a data conflict → can't regress the wave; byte-gate stays sole arbiter). **BYTE-PROOF (no Fable5):** full *loose* func_80129CF8 (intended decls, un-cast) → `reconcile_decls` (5 reconciled) → swapped into the `DEFINE_` macro → `make build BINARY=ov_SC01_077` = **`d19c9580` BYTE-IDENTICAL**; idempotent (0) on the canonical committed draft. **T4 resolved NO-OP** (T1: zero per-member conflicts — the fleet is decl-consistent). Distilled (R30): cookbook **§33** + §32 R14-correction, SETUP inventory row, design-doc **✅ RESOLVED** banner. **NEXT (T5, on Drew's Fable5 go):** match a sibling giant — `func_80138ED0` (closest, 2 data bases D_80127548/D_80127C0C) — with Fable5Max → `reconcile_decls` its raw draft → bank ×1 → `dedup_propagate --recover` ×134 (the real end-to-end proof + a 2nd giant ×134). Then T6 finalize + PhaseEnd.
|
||||
- **T7b/T1 — R14: the "×134 wall" was a MISDIAGNOSIS; `func_80129CF8` banks ×134 FREE (2026-07-03, this commit):** Diagnosed the prior "×134 BLOCKED / all overlays excluded" claim by RUNNING it (R14/P9). Byte-verified: (a) the giant's ×1 bank extern block is already fleet-canonical (every symbol matches the overlay-majority; the lone `D_801151D4` `s32`-vs-`ptr` conflict is in `resident.c`, NOT an overlay member); (b) `dedup_propagate --addr 0x80129CF8 --check-only` → plan-eligible, **134 members**, passes `compiles_standalone`; (c) a representative member (`ov_SC01_000`) declares NONE of the giant's symbols locally (the macro's externs are the sole declarers); (d) controlled `--no-gate` instantiate + `make build BINARY=ov_SC01_000` = **BYTE-IDENTICAL** `9052dc0e`. Then full `dedup_propagate --addr 0x80129CF8 --recover` → **134 overlays byte-identical, group registered** (exit 0); clean `make clean && extract-all && check-all` → **136/136, 0 failed**, fleet **64.90→65.52%**, dedup **1799→1800/0**. ⇒ the "loose-typing wall" was a **stale-asm / incremental-tree artifact** (the exact T5c/T6-§A trap — a prior run before the reconcile committed, or a dirty asm/). **Consequence:** the reconcile tool is NOT needed to unlock func_80129CF8 (or any *already-reconciled* giant); its real value = **mechanize the manual decl-reconcile** for *freshly-matched* giant drafts (m2c `M2C_UNK` / Fable5 output with loose callee/data types) → canonical decl + byte-neutral access casts → bankable ×1 + propagatable ×134, hands-free. Beneficiaries: the **6 sibling giants** (all still stubs) + the wave tail. **Drew's choice B:** finish the tool + match a sibling giant as the real T5 validation target (Fable5Max on request). Plan `plan-…mossy-dawn.md` (T1–T6); next = T2 oracle + T3 `reconcile_decls.py`. Commit: (this).
|
||||
|
||||
Reference in New Issue
Block a user