phase11: merge 35 + 5-way re-partition — 556 bodies / 565 regions

Worker D's 0x80025ADC (136 B). Partitions re-interleaved 5 ways because workers B and C
are both at ~94% context and effectively exhausted, leaving 2 active workers against 45
remaining bodies. A fifth worker restores capacity.
This commit is contained in:
Christopher Williams
2026-09-24 10:32:46 -04:00
parent 9ff344834c
commit 887155a733
5 changed files with 980 additions and 794 deletions
+793 -794
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -81,6 +81,7 @@
0x800230E4 0x8002311C src/func_800230E4.c
0x80024C14 0x80024C34 src/func_80024C14.c
0x80025070 0x800250AC src/func_80025070.c
0x80025ADC 0x80025B64 src/func_80025ADC.c
0x80026180 0x800261C0 src/func_80026180.c
0x80026258 0x80026264 src/func_80026258.c
0x80026264 0x80026274 src/func_80026264.c
1 # Code-region registry: one C region per matched function.
81 0x800230E4
82 0x80024C14
83 0x80025070
84 0x80025ADC
85 0x80026180
86 0x80026258
87 0x80026264
+62
View File
@@ -0,0 +1,62 @@
/*
* func_80012918 — 72 bytes at 0x80012918..0x80012960
*
* Hypothesis, not a claim about meaning: releases a sub-object if one is attached —
* calling a helper with the parent plus an offset and the sub-object, then clearing the
* slot. A one-branch body; matched on the FIRST spelling as the third member of a family
* whose other members are already matched (src/func_8001289C.c has the identical shape).
*
* Original words:
* 27BDFFE8 addiu sp,sp,-24
* AFB00010 sw s0,16(sp)
* 00A08021 move s0,a1 ; s0 = a1
* 1200000B beqz s0,0x80012948 ; if (a1 == 0) skip everything
* AFBF0014 sw ra,20(sp) ; (delay)
* 8E050028 lw a1,40(s0) ; a1 = a1[10]
* 00000000 nop
* 10A00004 beqz a1,0x8001294C ; if (a1[10] == 0) skip the call
* 00001021 move v0,zero ; (delay) v0 = 0
* 0C009958 jal 0x80026560 ; func_80026560(a0 + 0x90, a1[10])
* 24840090 addiu a0,a0,144 ; (delay)
* AE000028 sw zero,40(s0) ; a1[10] = 0
* 00001021 move v0,zero ; 0x8001294C: v0 = 0
* 8FBF0014 lw ra,20(sp) ; 0x80012948:
* 8FB00010 lw s0,16(sp)
* 27BD0018 addiu sp,sp,24
* 03E00008 jr ra
* 00000000 nop
*
* **FAMILY MATCH.** `src/func_8001289C.c` (72 bytes, the same histogram and size) is
* `if (a1 != 0 && *a1 != 0) { func_80026560(a0 + 0x94, *a1); *a1 = 0; } return v0;`
* and this row is that with a different field offset and a different parent offset. The
* two byte-required details are both inherited from the sibling:
*
* 1. **The guard is the `&&` chain** `a1 != 0 && a1[10] != 0` — cc1 emits `beqz s0` for the
* first term and `beqz a1` for the second, with the `move v0,zero` in the second
* branch's delay slot.
* 2. **`v0` is a real local initialised to 0 and returned**, not a `return 0;` — the
* original has `move v0,zero` in a branch delay slot AND at the join, which is what an
* initialised-and-returned local produces.
*
* The field is at byte offset 40 (int index 10) and the parent offset is 0x90, whereas the
* sibling uses 0 and 0x94 — the same body with different constants, which is exactly what
* the family score of 1.000 predicted.
*
* LIMITS: the function name, the callee, both offsets and the "release the sub-object"
* reading are hypotheses taken from the instruction shape; only the bytes are evidence.
* func_80026560 is declared here rather than registered.
*/
extern void func_80026560(int a0, int a1);
int func_80012918(int a0, int *a1)
{
int v0 = 0;
if (a1 != 0 && a1[10] != 0) {
func_80026560(a0 + 0x90, a1[10]);
a1[10] = 0;
}
return v0;
}
+56
View File
@@ -0,0 +1,56 @@
/*
* func_800259A0 — 60 bytes at 0x800259A0..0x800259DC
*
* Hypothesis, not a claim about meaning: forwards to a helper, substituting a word from a
* sub-object when one is present and zero when it is not, and passing the original second
* argument through as the third. A leaf-sized body with one branch — it matched on the
* FIRST spelling, and it is the third member of a family whose other members are already
* matched (src/func_80025070.c has the identical shape).
*
* Original words:
* 27BDFFE8 addiu sp,sp,-24
* AFBF0010 sw ra,16(sp)
* 8C820020 lw v0,32(a0) ; obj2 = *(int **)((char *)a0 + 0x20)
* 00000000 nop
* 14400004 bnez v0,0x800259C0 ; if (obj2 != 0) -> the else arm
* 00A03021 move a2,a1 ; (delay) the ORIGINAL a1 becomes the 3rd argument
* 08009671 j 0x800259C4
* 00002821 move a1,zero ; (delay) then-argument: 0
* 8C410020 lw a1,32(v0) ; 0x800259C0: else-argument: obj2[8]
* 0C009635 jal 0x800258D4 ; 0x800259C4: func_800258D4(a0, a1, a2)
* 00000000 nop
* 8FBF0010 lw ra,16(sp)
* 27BD0018 addiu sp,sp,24
* 03E00008 jr ra
* 00000000 nop
*
* **FAMILY MATCH: THE SOURCE SHAPE IS THE SIBLING'S, VERBATIM.** `src/func_80025070.c`
* (60 bytes, the same opcode histogram and the same size) is
* `if (obj2 == 0) func_800250AC((int)a0, 0, a1); else func_800250AC((int)a0, *(int *)((char *)obj2 + 0x20), a1);`
* and this row is that with a different callee. **Writing the `if` as `obj2 == 0` with the
* zero arm FIRST is byte-required**: cc1 emits `bnez v0,<else>` with the zero case as the
* fall-through path, and the original's `j 0x800259C4 / move a1,zero` in the delay is
* exactly that layout. Note the THIRD argument is the *original* `a1`, captured in the
* branch delay slot before `a1` is overwritten — so the source must pass `a1` (not a copy
* made after the branch) as the third argument.
*
* The family was found by `./tools/sf3_family` (opcode-histogram cosine × size ratio against
* already-matched regions). This row scored 1.000 against `0x80025070` — identical histogram,
* identical size — and that is what made it a one-attempt row.
*
* LIMITS: the function name, the callee, the sub-object offset (0x20) and the meaning of the
* forwarded word are hypotheses taken from the instruction shape; only the bytes are
* evidence. func_800258D4 is not registered and is referenced by its address-named spelling.
*/
void func_800258D4(int, int, int);
int func_800259A0(int *a0, int a1)
{
int *obj2 = *(int **)((char *)a0 + 0x20);
if (obj2 == 0)
func_800258D4((int)a0, 0, a1);
else
func_800258D4((int)a0, *(int *)((char *)obj2 + 0x20), a1);
}
+68
View File
@@ -0,0 +1,68 @@
/*
* func_8006B2D4 — 84 bytes at 0x8006B2D4..0x8006B328
*
* Hypothesis, not a claim about meaning: walks a singly-linked list from a global head and
* calls a teardown routine on every node that has a flag set. Matched on the FIRST spelling
* as the third member of a family whose sibling is already matched (src/func_8006ADB0.c has
* the identical shape and differs only in the callee).
*
* Original words:
* 8F820550 lw a0,1360(gp) ; node = D_80121E88 (hoisted above the frame)
* 27BDFFE8 addiu sp,sp,-24
* AFBF0014 sw ra,20(sp)
* 10800009 beqz a0,0x8006B314 ; while (node != 0)
* AFB00010 sw s0,16(sp) ; (delay)
* 8C82000C lw v0,12(a0) ; 0x8006B2E8: mid = node[3]
* 00000000 nop
* 8C410160 lw v1,352(v0) ; flag = *(int *)(mid + 352)
* 8C50018C lw s0,396(v0) ; next = *(int *)(mid + 396)
* 10600004 beqz v1,0x8006B308 ; if (flag != 0) func_800C022C(node)
* 00000000 nop
* 0C03008B jal 0x800C022C
* 00000000 nop
* 02002021 move a0,s0 ; 0x8006B308: node = next
* 1480FFF7 bnez a0,0x8006B2E8 ; more -> loop
* 00000000 nop
* 8FBF0014 lw ra,20(sp) ; (END)
* 8FB00010 lw s0,16(sp)
* 27BD0018 addiu sp,sp,24
* 03E00008 jr ra
* 00000000 nop
*
* **FAMILY MATCH.** `src/func_8006ADB0.c` (84 bytes, identical histogram and size) is the
* same walk with `func_800BFF20` as the callee. Two details are inherited from it and are
* byte-required:
*
* 1. **`next` is read BEFORE the call** (`lw s0,396(v0)` precedes the `jal`) — the loop
* pointer therefore does not survive the call and the next pointer lives in a
* callee-saved register. Reading the next pointer after the call changes the bytes.
* 2. **The head is hoisted above the frame setup** (`lw a0,1360(gp)` is the first
* instruction), which is what a `while (node != 0)` over a global produces.
*
* This row calls `func_800C022C`, a 464-byte row I classified as a near-miss earlier in the
* session — the same sub-object layout (`mid + 352`, `mid + 396`) appears in both, which is
* further evidence that the family spans both directions of the call graph.
*
* LIMITS: the function name, the callee, the global head, the node offsets (3, 352, 396) and
* the whole "walk and tear down" reading are hypotheses taken from the instruction shape;
* only the bytes are evidence. Both symbols are referenced by their address-named spellings.
*/
extern int D_80121E88;
extern void func_800C022C(int *node);
void func_8006B2D4(void)
{
int *node = (int *)D_80121E88;
while (node != 0) {
int *mid = *(int **)((char *)node + 12);
int *flag = *(int **)((char *)mid + 352);
int *next = *(int **)((char *)mid + 396);
if (flag != 0)
func_800C022C(node);
node = next;
}
}