Files
BFM-decomp/cookbook/C0032.md
T

4.4 KiB
Raw Blame History

§30 — Fable5Max cracks §20/§10 "unsteerable" from the gcc SOURCE: store-vs-load is a /s aliasing flag, the def-side wall has a macro escape, + the birthing-boost (Phase 23, byte-proven on giant func_8014EE14 248 ins ×134)

A single Fable5Max agent (an Agent with model: fable, given the target asm + tools/ghidra_c/ + this cookbook + the match_one→gate_stage loop) matched a 248-ins reach-134 GIANT on the §20/§10 store-vs-load wall — the class 22 phases of Opus/GLM called "CONFIRMED unsteerable" — by reading the actual gcc-2.7.2 source (tools/reference/gcc-papermario) with -da RTL dumps. It banked ×134 (leaf MATCH (248 ins); whole-binary banked:1; check-all 136/136; dedup-check 1780/0). The §29 "not a bigger model" verdict is corrected: a frontier model that goes to the compiler INTERNALS is a wall-breaker for the codegen classes. Three byte-proven idioms:

  1. STORE-vs-LOAD IS A DETERMINISTIC ALIASING FLAG, NOT A SCHEDULER TIE-BREAK (revises §10/§20 "unsteerable"). gcc-2.7.2 expr.c sets MEM_IN_STRUCT_P (/s) only when a load's address is a member/aggregate ref or was "computed by addition" (PLUS_EXPR). The front end folds p[0]→*p, so zero-offset / bare-deref loads never get /s → they carry a hard true-dependence on an aliasing fixed-symbol store (D_xxx = 0) and get stuck below it; offset/member loads have /s and hoist freely. So the store-vs-load "coin-flip" is a binary flag you SET from C:
    • Grant /s (make the load hoist over the store): write it as a struct-member ref → ((struct { s32 field; } *)p)->field. Use an ANONYMOUS struct in the cast — dedup_propagate (line ~366) rejects inline named structs, so anonymous keeps the /s flag AND stays propagatable ×134.
    • Deny /s (keep the load below the store, e.g. a separate reload the target shows): keep it a bare *p / p[0]. (CSE's fixed-scalar-store invalidation only kills non-/s entries — that's what forces the target's separate reload.)
    • The tell in any diff: a zero-offset pointer load stuck on one side of a fixed-symbol store while offset loads float. Re-test candidates: func_8014F2E0, func_80150528, func_8014EA4C (close=6), and every §10/§20 "store-vs-load unsteerable" backlog verdict.
  2. THE DEF-SIDE RETURN-TYPE WALL HAS A MACRO ESCAPE (extends §29). When a matching def must return s32 (a void return DCEs a computed local → frame shrinks → no match) but the only conflicting caller-decl is a shared DEFINE_func_* macro that DISCARDS the return: widen that macro's extern void func_X(...) → extern s32 func_X(...). It's byte-neutral for the caller (the return is discarded — verified check-all 136/136 fleet-wide). §29 said "no escape" because a bare INCLUDE_ASM stub declares no C symbol — but a macro DOES declare the symbol via its extern line, so there is one. (The narrow-scalar-param-by-value wall from §29 still stands — this dissolves only the return-type conflict.)
  3. THE "BIRTHING-BOOST" PROLOGUE-ORDER LEVER. sched.c:adjust_priority (pre-reload only) boosts to max priority any insn whose dest reg is set exactly once in the fn (birthing_insn_p: REG_N_SETS==1); sched1 schedules each bb backward, so a boosted insn is picked early = placed late. Single-set param copies (s0=a0) then sink below multi-set const inits (s6=0/s5=8, reassigned in a switch → never boosted). Fix: one zero-byte NON-volatile re-tie __asm__("" : "=r"(x) : "0"(x)) on the param, placed in a LATER basic block (after the switch). It counts as a 2nd SET (boost dead), emits nothing, adds no bb0 edges → all inits tie and the LUID/source-order tie-break restores params-first. Generalizes to any wrong prologue/init ORDER between single-set and multi-set defs.

Meta-lesson (feeds effort-map / R17): the "idiom well is dry / wall is intrinsic" verdict (T10.8/T10.9, §29) was model-relative — true for GLM and the local 7B, false for a frontier model that reads the gcc-2.7.2 source. The wall-breaker recipe: Agent(model:fable) + tools/reference/gcc-papermario (RTL -da dumps) + this toolkit + the match_one/gate_stage loop, on ONE giant at a time. Cost ≈ 375k agent-tokens / giant across the leaf-crack + whole-binary integration (2 rounds). NB: match_one (isolated) masks in-TU declaration conflicts — always finish on the whole-binary gate_stage (the §20 stale-.o trap can fake a pass; force a clean compile).