phase10: merge 26 — 482 distinct bodies / 491 regions

+2 bodies (worker C2 claims 1-2: 0x80051864 88 B, 0x8006AA10 120 B). Candidate
gate MATCH before promotion. make check green: regions=491 AGREE,
differing_bytes=0 MATCH, 237 tests OK.

C2 also confirmed the paired named-boolean rule exactly as broadcast (one shared
li a3,1 across four acceptance paths; nested ifs give two blocks and 124 B
LENGTH-MISMATCH; the single combined condition is byte-identical), and caught the
mask 0x00400000 vs 0x40000000 by computing the lui high half.

CROSS-CUTTING FINDING (worker C2, recorded for the cookbook): THREE of C2's four
negatives are the -O2 SCHEDULER, not source shape. Diagnostic: when the length is
exactly right and the residual is a permutation of a few instructions whose
-fno-schedule-insns build matches the original, stop hunting for a source shape.
Trap: on 0x80016F80 sched OFF gives the original's ORDER but the wrong allocation
while sched ON gives the right allocation and the wrong order, so neither alone
matches. C2 correctly did NOT take the scheduler override; all three stay recorded
as negatives with the lever named.

Also: the commutative-operand lever has a COUPLED ALLOCATION side-effect
(0x80027744, 0x80050674) -- every spelling giving the original's addu operand order
also flips which value takes v0 vs v1, because operand order changes pseudo creation
order. Finding 22's re-spell advice is necessary but not sufficient.
This commit is contained in:
Christopher Williams
2026-09-24 08:20:05 -04:00
parent a7b842faf5
commit be2ee1874c
4 changed files with 1350 additions and 1226 deletions
+1224 -1226
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -179,6 +179,7 @@
0x800504E4 0x80050548 src/func_800504E4.c
0x800516E0 0x800516FC src/func_800516E0.c
0x8005182C 0x80051864 src/func_8005182C.c
0x80051864 0x800518BC src/func_80051864.c
0x80052C98 0x80052CAC src/func_80052C98.c
0x80057524 0x80057564 src/func_80057524.c
0x80057564 0x800575C4 src/func_80057564.c
@@ -222,6 +223,7 @@
0x80068F98 0x80068FA8 src/func_80068F98.c
0x800697A4 0x800697C4 src/func_800697A4.c
0x800697C4 0x800697FC src/func_800697C4.c
0x8006AA10 0x8006AA88 src/func_8006AA10.c
0x8006ADB0 0x8006AE04 src/func_8006ADB0.c
0x8006B184 0x8006B1CC src/func_8006B184.c
0x8006B1CC 0x8006B214 src/func_8006B1CC.c
1 # Code-region registry: one C region per matched function.
179 0x800504E4
180 0x800516E0
181 0x8005182C
182 0x80051864
183 0x80052C98
184 0x80057524
185 0x80057564
223 0x80068F98
224 0x800697A4
225 0x800697C4
226 0x8006AA10
227 0x8006ADB0
228 0x8006B184
229 0x8006B1CC
+55
View File
@@ -0,0 +1,55 @@
/*
* func_80051864 — 88 bytes at 0x80051864..0x800518BC
*
* Hypothesis, not a claim about meaning: a leaf predicate that recognises two
* global object handles and, for those, walks a three-level pointer chain and
* returns whether a word at the end is at least 2.
*
* The observed instructions are:
* lui v0,0x8013
* lw v0,-10340(v0) v0 = D_8012D79C
* nop (load delay)
* beq a0,v0,0x8005188C if (a0 == D_8012D79C) goto body
* nop (delay slot)
* lui v0,0x8013
* lw v0,-8912(v0) v0 = D_8012DD30
* nop (load delay)
* bne a0,v0,0x800518B0 if (a0 != D_8012DD30) goto ret0
* nop (delay slot)
* lw v0,32(a0)
* nop (load delay)
* lw v0,244(v0)
* nop (load delay)
* lw v0,492(v0)
* nop (load delay)
* sltiu v0,v0,2
* j 0x800518B4 return (word >= 2)
* xori v0,v0,0x1 (delay slot)
* move v0,zero return 0
* jr ra
* nop
*
* `sltiu` (not `slti`) means the final comparison is UNSIGNED, so the word at
* the end of the chain is declared `unsigned int`. The `beq`-to-body /
* `bne`-to-return pair is the `||` short-circuit; the body's `return` is a
* forward `j` to the shared return label while the `return 0` block falls
* through into it.
*
* LIMITS. The two globals' types are unknown; they are declared `unsigned int`
* only because they are compared against a word-sized argument. Every offset
* (32, 244, 492) is a raw disassembly reading with no evidence for a struct
* layout, so the chain is written as explicit pointer arithmetic. The return
* value's meaning is unknown.
*/
extern unsigned int D_8012D79C;
extern unsigned int D_8012DD30;
int func_80051864(unsigned int a0)
{
if (a0 == D_8012D79C || a0 == D_8012DD30)
return *(unsigned int *)(*(unsigned int *)(*(unsigned int *)(a0 + 32)
+ 244)
+ 492) >= 2;
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
/*
* func_8006AA10 — 120 bytes at 0x8006AA10..0x8006AA88
*
* Hypothesis, not a claim about meaning: a leaf predicate. It walks two levels
* of a structure hung off the first argument, tests one bit of a control word,
* then accepts the object if any of three secondary conditions holds; a bit in
* a word at +260 of the second argument also accepts it. All four acceptance
* paths share ONE `a3 = 1` block, which is what makes the code compact.
*
* The observed instructions are:
* lw a2,8(a0) a2 = *(a0 + 8)
* nop (load delay)
* lw v0,16(a2) v0 = *(a2 + 16)
* nop (load delay)
* lw v0,40(v0) v0 = *(v0 + 40)
* lui v1,0x40
* and v0,v0,v1 v0 &= 0x40000000
* beqz v0,0x8006AA68 if (!(word & 0x40000000)) goto L2
* move a3,zero (delay slot) a3 = 0
* lw v0,12(a0) if (*(a0 + 12) == 0) goto ret1
* nop
* beqz v0,0x8006AA7C
* nop
* lbu v0,8(a2) else if (*(unsigned char *)(a2 + 8) & 0x10) goto ret1
* nop
* andi v0,v0,0x10
* bnez v0,0x8006AA7C
* nop
* lw v0,24(a2) else if (*(a2 + 24) == 0) goto ret1
* nop
* beqz v0,0x8006AA7C
* nop
* lw v0,260(a1) L2: v0 = *(a1 + 260)
* nop
* andi v0,v0,0x100 if (v0 & 0x100) ...
* beqz v0,0x8006AA80
* nop
* li a3,1 ret1: a3 = 1
* jr ra
* move v0,a3 (delay slot) return a3
*
* The `||` chain is what makes the three secondary tests share the single
* `a3 = 1` block, and the second `if` reaches the same block; cc1 cross-jumps
* all four acceptance paths onto the one `li a3,1`. `lbu`/`andi 0x10` (rather
* than `lhu` or `lw`) fixes the byte field at +8 as an unsigned char, and the
* two `and` masks (0x40000000, 0x100) are materialised as `lui 0x40` and an
* `andi` respectively, so the first is a plain `int` bit test.
*
* LIMITS. Every offset (8, 16, 40, 12, 8, 24, 260) is a raw disassembly
* reading with no evidence for a struct layout, so the walk is written as
* explicit pointer arithmetic. The two arguments' types, the meaning of the
* masks and the return value are unknown.
*/
int func_8006AA10(int a0, int a1)
{
int a2;
int a3;
a2 = *(int *)(a0 + 8);
a3 = 0;
if ((*(int *)(*(int *)(a2 + 16) + 40) & 0x00400000)
&& (*(int *)(a0 + 12) == 0
|| (*(unsigned char *)(a2 + 8) & 0x10)
|| *(int *)(a2 + 24) == 0)
|| (*(int *)(a1 + 260) & 0x100))
a3 = 1;
return a3;
}