Files
BFM-decomp/cookbook/C0330.md
T

2.7 KiB

§296 — THE FRAME CHECK OUTRANKS THE ATLAS LEVER: READ PROLOGUE/EPILOGUE BEFORE DRAFTING ANY C — A REAL TELL CAN LIVE INSIDE AN UNREACHABLE FRAGMENT (P31 S61; wave m0a, 16 cards byte-proven; extends §179-C)

SIXTEEN m0a cards carried a genuine atlas lever — mostly extend-tell, and the sll/sra pairs ARE in the targets — on symbols that are splitter FRAGMENTS: no prologue, no epilogue, exits by bare j <sibling> with live-out $t registers, or entry state arriving in registers no C calling convention expresses. Every C draft gains the phantom teardown (§179-C: no sibcall pass; expand_function_end always appends), so the drafts plateau at +2..+7 instructions REGARDLESS of how well the lever is played — the lever is real and unreachable at once.

The routing law: before spending one compile on any card's lever, read the target's FRAME. Greppable in seconds: no trailing jr $ra; an exit j <named sibling>; endlabel abutting the next glabel; a frame adjust riding a delay slot; a *_OBJ_NN-suffixed symbol. Any of these ⇒ the §179-C/§265 file-scope blob lane, and the lever's knowledge banks as a COMMENT in the blob, not as C. Fragment chains bank in link order so shared-tail fallthroughs resolve (func_8005AC24 → SYS_OBJ_1A30 → SYS_OBJ_1A70; RotMatrixYXZ → FGO_02_OBJ_68 → _CC → _160). The banked comment src/800b_5.c:44-46 states the class exactly: "FGO_01_OBJ_64 ... is NOT a callable function: it is the second code FRAGMENT of one larger routine (func_8004978C -> FGO_01_OBJ_64 -> FGO_01_OBJ_CC -> FGO_01_OBJ_160)."

The liveness-proof pattern (before believing a computation trio is dead and letting DCE eat it): read the SIBLING fragment's opening instructions — FGO_02_OBJ_CC opens multu $t4,$t0 and stores $t6, values only the upstream arms wrote; liveness crosses two fragment boundaries (RotMatrixYXZ card).

THE BOUNDARY, byte-proven the same night: a fragment that legitimately returns via jr $ra is NOT in this class. SYS_OBJ_1AF0 banked as PLAIN C with register pins (src/800c.c:1873):

s32 SYS_OBJ_1AF0(void) {
    register s32 r_v0 __asm__("v0");
    register s32 r_v1 __asm__("v1");
    r_v0 |= 0xE5000000;
    return r_v1 | r_v0;
}

— the constant-OR kept as its own statement (fusing it lets gcc commute the pair), the tail spelled r_v1 | r_v0 for operand order. The frame check, not the fragment-looking label, decides the lane.

Cards: RotMatrixYXZ/RotMatrixY/RotMatrixX · func_8004978C · func_80049CAC · FGO_01_OBJ_64 · FGO_02_OBJ_68/_CC · FGO_03_OBJ_64 · SetDrawEnv · SYS_OBJ_1A30/1C28/2F7C · func_8005AC24 · VM_NO1_OBJ_31C (all banked as §179-C/§265 blobs) + SYS_OBJ_1AF0 (the C-side boundary).