5.6 KiB
§37 — The T7 §G giant endgame: 6/8 cracked, meta-laws + transferable levers (Phase 24, 2026-07-07; FULL byte-verified detail + gcc-2.7.2 line cites in docs/gcc-2.7.2-map/t7g-giant-harvest.md)
Cracked 6 of 8 reach-134 §G giants — func_801571C4 (permuter), func_8014EA4C/func_801372B0/func_801770E0/func_80176D94/func_80148094 (Fable5) — plus 2 genuine walls: func_80178004 (biv-init emit-order, close=7) and func_801412A8 (allocation placement-knot, close=29), both stay INCLUDE_ASM. 4 propagated ×134 (fleet 65.75→65.91%, clean 136/136); 372B0/770E0 banked ×1 (blocked ×134 by the §A pin/asm + local-type self-containment gaps).
META-LAWS (audit BEFORE deep work):
- SIBLING-ISOMORPHISM (mandatory step-0): GPU-packet/addPrim builders come in FAMILIES. Diff your target
.sMNEMONIC sequence vs already-MATCHED siblings (grep -oP '\*/\s+\K\S+'); an immediates-only diff ⇒ PORT the banked sibling verbatim + swap constants = one-shot (76D94 fell from 770E0 in ~15 min). - "MUTUAL-EXCLUSION / RC-6 unsteerable" IS A TELL, NOT A VERDICT: "X must be early AND late, coupled through one priority number / every small edit moves 20+ insns" = a MISSING dep edge or an allocno TIE — real only in the broken graph. 770E0 (the named RC-6 exemplar) fell fully source-reachable.
- RTL DUMPS ARE NOT STRIPPED (corrects §34): the shipped cc1 with
-dr -dj -dc -dl -dgemits full.rtl/.jump/.combine/.lreg/.greg— readable ground truth before gdb (.lregrefs/length,.gregalloc-order/conflicts/preferences,(use (reg:SIin.combine= phantom stack slots).
TRANSFERABLE LEVERS (byte-verified):
- The
/s-DEP LATTICE (load+store dual): forceMEM_IN_STRUCT_Pvia a struct-member-at-offset-0 access —((struct{u16 h;}*)&D_global)->h(load, 770E0) /((struct{u32 w;}*)p)->w=…(store, 76D94) — to restore the missing store↔load dep edge (sched.c:820drop clause needs one side /s+varying, the other non-/s+FIXED-address). SCOPE: inapplicable when all mem ops are register-addressed (412A8/48094). - Allocno-priority ref-boost (48094):
__asm__("" :: "r"(v));at the TOP of a block where v is already live-through → +1 flow-ref, 0 live-range, 0 bytes; crosses thefloor_log2(refs)step inallocno_compare(global.c:588) → v wins the reg over a short block temp. - Coalescable-copy insn_count bump (78004): whole reg-file shifted by one hoisted loop const ⇒
move_movables' threshold at its>=boundary — a coalescable copy{u32 m=v; store=m|…;}bumps insn_count +1 → hoist refused; combine coalesces m away = 0 bytes. BANKABLE (vs a TU-wide global-register-var). - Const-register PIN cascades store order (770E0): store order is downstream of a const's register via sched2 anti-webs → pin the const (
register u32 c __asm__("$6")=…), stores re-place free. - S2-kill re-tie (372B0):
__asm__("":"=r"(v):"0"(v))after last use → reg_n_sets==2 → no birthing boost → source order (single-set pins, INCL. hard-reg, DO boost — corrects §34). + S2 fire-tick via consumer store order. - qty_compare-TIE audit (412A8): dozens of "schedule" diffs often trace to ONE equal-priority allocno tie (
find_free_reg, gdb) broken by qty/block-scan order — a window-temp reuse flips it. + multi-death block-var law (local-alloc.c:472: reg_n_deaths≠1 → global allocno → chaos). - CSE-dodge without a barrier:
(u16)x(zero_extend) head vsx&0xffff(AND) tail hash differently → no cross-call CSE → no extra callee-save. Prefer overvolatile-asm re-ties (a FULL sched barrier per sched.c ASM_OPERANDS).
BANKING PATTERNS (main + _a split): caller-extern reconcile (void→canonical return, 571C4); asm-label alias for sibling-decl signedness/proto conflicts (extern u16 X __asm__("D_x"), 372B0) — beats reconcile's *(u16*)&D_x cast whose address-of PERTURBS regalloc; canonical call-cast + anonymize the shared /s struct for isomorphic-sibling ports (76D94). ×134 blockers (§A gaps → tool fixes): register-asm pins + overlay-local named types fail dedup_propagate.compiles_standalone → bank ×1 (needs a pin/asm self-containment shim + a uniquely-renamed type-lift).
TOOLING (flywheel): fixed a silent permuter bug — tools/p16_permute.py header comments broke cpp → decomp-permuter no-op'd (0s) on EVERY commented draft (strip_c_comments); a SECOND silent no-op of the same class (Phase 26 session 6): a draft whose GTE ops are #defines CONTAINING __asm__ (the PsyQ inline_c.h convention — i.e. most renderer code) got its macro DEFINITIONS chewed up by hide_asm (which is built for __asm__ statements / register pins and scans to the nearest ;{}), swallowing the function itself → pycparser Function <fn> not found in base.c → permuter no-op (0s). Fix: cpp_expand_macros() pre-expands with cpp -P so each GTE op becomes an inline __asm__ statement hide_asm can carry — applied ONLY when a #define ... __asm__ is present, so macro-free drafts are byte-untouched. LESSON: the permuter reporting no match (0s) is a TOOLING failure signature, never a real search result — always confirm workers actually ran. p16_permute also gained --asm-subdir (it was hardcoded to ov_SC01_077's main object, so no core in another overlay/split object could be permuted at all); NEW tools/permuter_ils.py (warm-restart iterated-local-search — descends where a cold run plateaus: 48094 72→29). Escalation: model to close=2 by hand, THEN directed-permuter the residual (372B0's last lever fell at permuter iter 291; permuter is low-ROI at close=8).