14 KiB
§294 — ADDENDA HARVESTED FROM THE S61 GEN0/MAXTOK/MAIN/DEEPSEEK BATCH (waves ab8/ab16/ab24/ab32 · g0a–g0f · m0a · ds1/ds2): 99 candidates, 52 covered, 15 notes → 10 addenda, 29 notes → 5 new laws (§295–§299), 3 refuted
Provenance. The night the ox window closed: the MAXTOK ABCD arms (ab8/ab16/ab24/ab32, same 10
functions per arm), the gen0 overlay sweep (g0a–g0e) plus its feedback-armed redraft wave (g0f), the
main-EXE gen0 push (m0a — 57 notes, the richest ore: boot/-O0, the libapi stub cluster, and the
splitter-fragment families), and DeepSeek's first two batches (ds1/ds2 — a NEW source; calibration in
§300). Every claim below was verified against the banked C in src/ and, where the stale .s
survives, the target bytes; three claims died at that check and are named in §300. 52 of 99 notes
were already owned by §§1–293 — the healthy majority, mostly honest "nothing new — §X carried it"
self-reports.
ADDENDUM to §127 — the -O0 constant-offset fold keys on the MEMBER-ACCESS tree shape, not on the index being constant
§127's dichotomy (p->f folds the offset into the displacement; p[i] computes the address first)
reads as constant-vs-variable. func_800D1B00 (md_MAIN_011, MATCH, wave g0d) sharpens it: even a
COMPILE-TIME-CONSTANT subscript through a cast-indexed form — ((s32*)p)[3] — materializes
addiu $v0,$v1,12 + sw $v1,0($v0) at -O0, 2 instructions per statement (a 72-insn drift over the
~49-store block, per the drafting A/B). The fold fires on the COMPONENT_REF tree shape only. The
banked spelling (src/md_MAIN_011/md_MAIN_011.c:552) is a FUNCTION-LOCAL typedef with exact field
offsets plus member stores:
void func_800D1B00(void) {
typedef struct {
s32 pad00;
s32 f04; s32 f08; s32 f0C; /* ... exact offsets through f94 */
} St78;
St78 *p = (St78 *)D_80078E78;
p->f04 = 0;
p->f08 = 0x258;
...
}
At -O0 only offsets matter, so the local typedef name is free (no §236-4 risk at block scope). When a
target's -O0 store run shows sw rX, K(rBase) with folded displacements, the source MUST be member
lvalues; when it shows per-statement addiu + 0-displacement stores, it must be the indexed/cast
form — §127's law, now stated for stores and for constant subscripts.
ADDENDUM to §261a — FOUR MORE -O0 DIALS BEYOND THE RELOAD COUNT (boot.c + md_MAIN_011/003, wave m0a/g0a/g0f, byte-proven)
(a) The register-local RMW three-spelling dial. func_80011A3C (boot, MATCH 40/40): banked
src/boot.c:671:
register u16 x;
x = *(u16 *)(p + 0xA3C0);
x = x + 1;
*(u16 *)(p + 0xA3C0) = x;
→ target (asm/nonmatchings/boot/func_80011A3C.s): lhu $v1,-0x5C40($at) / addiu $a0,$v1,0x1 /
addu $v1,$a0,$zero / sh $v1,-0x5C40($at) — the PLAIN-ASSIGNMENT pair loads into the variable's
own pseudo, adds into a FRESH pseudo, and copies back. Per the drafting A/B: compound += folds the
copy-back away (−1 ins); single-statement x = *mem + 1 loads into a temp first (REGALLOC-PERM).
§219 is this dial's -O2 counterpart; §261a's reload rows are the through-pointer face — this is the
register-local face.
(b) Scale-by-4: spell the SHIFT, not the multiply. func_80010A08 (boot, MATCH): banked
src/boot.c:255:
q = (arg0 + 3) / 4;
old = D_800A5E60;
D_800A5E60 += q << 2;
q * 4 routes through the mul-style expansion (frame reload into $v0 + a move); q << 2's
ashift expansion reads the frame slot straight into the shift's operand register — the target's
shape. One token closed a 16-mismatch residual. The compound += is also load-bearing (puts the
sll before the second global load; a plain a = b + c emits the load first). The dead
register u8 *p = D_800AF630; above these lines is the §127-family unused-register-local orphan
hi/lo pair — transcribe it, don't clean it.
(c) The register-pointer far-offset base lands CALLER-saved when the body has NO calls. The
banked boot family (func_80011A3C/func_80011ADC/func_800119F0/func_80011818/func_800118AC,
all register u8 *p = D_800AF630;) keeps the base in $v0/$v1 — NOT a callee-saved register —
with each >0x7FFF member offset assembling to the lui $at,(0x10000>>16) / addu $at,$v0,$at /
sh -0x5Cxx($at) split. The TU comment (src/boot.c:203-207) attributes callee-saved placement to
register; with zero calls nothing forces a saved reg — register's load-bearing effect is
suppressing the frame SPILL (drop it → base spills, frame grows), and a bare-symbol spelling instead
folds each far access into its own single %hi/%lo anchor (the 11-ins short form) even when
§261a's reload grammar is silent (no reloads exist). Promoted from the source comment per §127b's
standing rule.
(d) Routing note — the fleet's TERMINAL state for an -O0 function stranded in an -O2 TU is the
§265 verbatim-asm block IN THAT TU, not (yet) the §18/§261 _o0 carve: src/md_MAIN_003/ md_MAIN_003.c carries five banked instances (func_800D0174, func_800D0204, func_800D0440,
func_800D09A0, func_800D3204-family). §116/§126/§261 prescribe the build-graph move; until an
_o0 object exists for the TU, bank via §265 form 1 with the recovered C preserved in a comment
(waves ab16/g0f). corpus.stubs() counts these as matched though they are transcription, not decomp
— §265's accounting caveat stands.
ADDENDUM to §264-3 — the explicit entry copy's BOUND: required exactly when the RAW value must outlive the call that consumes only the PROMOTED value
§264-3 warns that a self = arg0 local emits double moves and says to use the parameter itself.
func_80012ABC (main, MATCH 18/18, wave m0a) is the bound: the raw parameter feeds the RETURN sum
while only its (s16) promotion feeds the call. Banked src/800.c:613:
s32 func_80012ABC(s32 a0, s32 a1, s32 a2)
{
s32 s0 = a0;
return (s0 + func_80012B04((s16)s0, (s16)a1, (s16)a2)) & 0xFFF;
}
The explicit copy is required AND free here — it survives as the target's addu $s0,$a0,$zero
because $a0 is immediately re-consumed by the promoted first argument. Typing the parameters s16
instead promotes into $s0 and adds a move $a0,$s0 (near-3). Single-basic-block functions obey the
same law as §264-3's multi-path exemplar: the decider is raw-value liveness past the call, not
control flow.
ADDENDUM to §172b-1 (counter-type dial) — the sll's SOURCE REGISTER is the placement discriminator
The §172b-1 addendum's dial 1 (declare the counter s16) and §264-4 (mirror a memory slot) both
produce a naked sll/sra pair — same count, different SOURCE register. Read which register the
sll consumes: func_80014588 (main, MATCH 25/25, wave m0a) shows the pair reading $v0 — the
addiu increment RESULT — not the counter's allocated home ($s1), with no memory slot in sight ⇒
dial 1: the counter itself is s16 (banked s16 i; at src/800.c:1241), keeping gcc in HImode
across the increment so the promotion applies to the increment pseudo. An s32 counter with (s16)i
casts emits the pair reading $sN — right count, wrong source register, unfixable by placement.
Pair reads a register that mirrors a store ⇒ §264-4's multi-def variable. Pair reads a call result ⇒
§264 recipe 1 / return-narrowing. One register read replaces a four-placement search.
ADDENDUM to §276 — the SHARE direction: spell the second adjacent symbol RELATIVE to force ONE anchor
§276's law covers the SPLIT direction (mix spellings so cse cannot unify repeated uses).
func_80018918 (main, MATCH 36/36, wave m0a) is the same dial's other end. The target folds two
adjacent-symbol call arguments onto ONE lui/addiu anchor plus addiu $a1,$a0,0x4C; two
independent externs (&D_80078DA0, &D_80078DEC) can never fold — no pass discovers that two
SYMBOL_REFs are numerically adjacent. Banked src/800.c:5098:
func_8005F0C8(&D_80078DA0, &D_80078DA0 + 0x4C);
Write the second symbol AS an offset off the first and the shared anchor is forced (this was the
whole 5-insn residual). Target shows one anchor + register-relative addiu for what the seed calls
two symbols ⇒ relative spelling; target shows independent %hi/%lo per use ⇒ §276's split rules.
ADDENDUM to §31's density-dummy dial (L2460/L2497) — the dose is TWO refs, and the dummy must sit where the loser is live-through
func_800348A8 (main, MATCH 29/29, wave m0a): a genuine allocno tie (i: 6 refs / long range vs
q: 5 refs / short range — either loses on density) did NOT flip with one extra ref anchored outside
the loop. TWO operand refs of the same variable, placed as the FIRST statement of the loop body —
inside the region where i is live-through — flipped the allocation (12 → 4 residual, class became
permuter fuel). Banked src/800.c:19141:
do {
__asm__ ("" :: "r"(i), "r"(i));
if (p[0] == five && q[-1] == lo) {
L2497's one-ref lift was measured on a floor_log2 power-of-two crossing (3/10→8/11); off such a
boundary, budget two refs and place them in the contested live range, not at the def.
ADDENDUM to §282 — the ADDRESS-GIV face: write the walked address INLINE so strength reduction births the induction register at loop.c's own insertion point
§282's mechanism (gcc's own late loop transformation places its new register's init AFTER the hoisted
movables — a position no source statement can reach) also governs a strength-reduced ADDRESS.
func_80034650 (main, MATCH 32/32, wave m0a), banked src/800.c:19069:
pm = (param_2 & 0xFF) << 16;
for (i = 0; i < 8; i++) {
if (*(param_1 + i + 0x3A) != 0) {
func_80030D80((Ent30D80 *)(D_800A4988 + i * 0x54), pm >> 16);
}
}
Writing the entity address INLINE as D_800A4988 + i * 0x54 lets strength reduction create the $s1
induction register itself and schedule its %hi/%lo materialization AFTER the pm computation,
matching the prologue order. An explicit e = D_800A4988; pointer-local init is a source statement
whose LUID precedes the movables — it always schedules first (6-mismatch plateau, unfixable by
statement reordering). The masked product is held in a named local (pm) and the >> 16 spelled at
the call site. Same law as §282's reversed counter; the tell is a loop-carried address register whose
init sits after other pre-loop work.
ADDENDUM to §253 — SECOND byte-proven card (upgrade from single-observation), and the placement face: postfix-in-condition parks the RMW store in the branch delay slot
§253 asked for cross-confirmation. func_800CB168 (md_MAIN_018, 112 ins, wave ds1 — DeepSeek's
first distilled card) supplies it, on the PLACEMENT axis: banked
src/md_MAIN_018/md_MAIN_018.c:128-207:
if ((*(s32 *)(obj + 7))++ & 3) {
goto L288;
}
The postfix-in-condition spelling tests the OLD value and leaves the incremented word's store free to
sink into the bnez delay slot — the compound/two-statement forms pin the store before the branch.
Same card, two more tree-verified spellings: a call result needs its OWN fresh local
(r = rand(); ...= r & 0xFFF; ...= (r & 1) + 2; — assigning into the live dispatch variable forces a
move v1,v0), and the L288 store chain D_80126BC8 = D_80126BCA = D_80126BCC = 0x1000; confirms
§145(c)'s descending store order word-for-word (stores BCC, BCA, BC8). §165-06 owns the expand face,
§253 the allocator face, this card the reorg/placement face of one axis: postfix vs compound is a
THREE-pass dial.
ADDENDUM to the L1800 anchor-steer bullet — a DERIVED-POINTER local silently flips the merged giv's anchor END
func_8019131C (ov_SC06_033, MATCH 97/97, wave g0f): carrying q = p + 1 as its own local made
combine_givs rebase the merged giv set on the LARGEST offset (base p+0x20, negative displacements
−0x18/−0x12 — LENGTH-DRIFT/2); deleting q and spelling every access off p in ELEMENT units —
banked src/ov_SC06_033/ov_SC06_033_jr_8018D98C.c:5030:
if (*p == 0x350) {
*(s32 *)(p + 4) = *(s32 *)(arg0 + 8);
*(u32 *)(*(s32 *)(p + 0x10) + 4) &= 0x7FFFFFFF;
*(p + 1) += 1;
}
p += 0x86;
— restored the target's smallest-offset base (p+2, positive displacements +6/+0x1E/0), which is what
L1800's own anchor law (last-recorded giv in program order — the *(p + 1) RMW is the final access)
predicts once there is a SINGLE base. Composition of §31-L2397 (collapse to one base pointer) with
L1800; the new fact: the derived pointer doesn't just risk a spurious IV — when the merge still
happens, it re-roots the anchor at the WRONG END, visible as sign-flipped displacements at the right
instruction count.
ADDENDUM to §31's asm→layout inference — TWO WIDTH-PAIR DISCRIMINATORS (same offset, different widths)
(a) lw feeding sh = a u16/s16 DESTINATION assigned from an s32 LVALUE. func_8017D3E4
(ov_SC04_006, MATCH, wave g0c), banked src/ov_SC04_006/ov_SC04_006_jr_8017BEBC.c:3394:
sp30[2] = *(s32 *)(self + 0x10); — the load carries the SOURCE's width (lw), the store the
DESTINATION's (sh). An lh+sh pair would mean an s16 source. Found by diff; no earlier section
names the pair.
(b) sw-of-result + lh-of-argument at the SAME offset = a WORD field read through an s16 cast,
not an s16 field. func_80180B80 (ov_SC03_111, MATCH 115/115, wave g0f), banked
src/ov_SC03_111/ov_SC03_111_jr_8017EC58.c:3688:
temp = func_80012C6C(*(s16*)&arg0->unk8, *(s16*)&arg0->unkC, 4);
*(s32*)&arg0->unk8 = temp;
The wide store + narrow read on one offset is what disambiguates the struct layout when either access
alone is ambiguous — the seed's packed s16-stride layout shifted every later offset by ±2..8.
Fields whose OTHER reads are lhu stay u16 with explicit (s16) casts at the narrow call sites.