phase9: merge 6 more — 281 regions / 272 distinct bodies

Worker A batch 9: if-conversion demo, pre-increment append, negate-magnitude,
guarded call pairs, epilogue-order-variant NEGATIVE 0x80100334 (finding 11's
'13 CRT sites' scoping corrected — this site is outside the CRT; recorded as
a third epilogue class data point), sched-tiebreak 0x8002515C. New symbol
D_80122160 (gp). Gate MATCH whole-binary SHA-1
e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
Christopher Williams
2026-09-24 00:32:22 -04:00
parent af9630b617
commit c160fa9326
8 changed files with 289 additions and 0 deletions
+6
View File
@@ -64,6 +64,7 @@
0x800276B0 0x800276D4 src/func_800276B0.c
0x800290D0 0x800290F0 src/func_800290D0.c
0x800290F0 0x80029118 src/func_800290F0.c
0x8002C6EC 0x8002C728 src/func_8002C6EC.c
0x8002C7BC 0x8002C7EC src/func_8002C7BC.c
0x8002C888 0x8002C894 src/func_8002C888.c
0x8002C894 0x8002C8A4 src/func_8002C894.c
@@ -95,6 +96,7 @@
0x80042D64 0x80042D88 src/func_80042D64.c
0x80043D8C 0x80043DC4 src/func_80043D8C.c
0x80044F58 0x80044FA4 src/func_80044F58.c gp=-D_80121BFC
0x80045388 0x800453C0 src/func_80045388.c
0x800453C0 0x800453F8 src/func_800453C0.c
0x8004C060 0x8004C090 src/func_8004C060.c
0x8004C090 0x8004C0AC src/func_8004C090.c
@@ -126,6 +128,7 @@
0x8006FA78 0x8006FAA0 src/func_8006FA78.c
0x8007049C 0x800704BC src/func_8007049C.c
0x80072BA8 0x80072BDC src/func_80072BA8.c
0x800734A4 0x800734DC src/func_800734A4.c
0x8007A404 0x8007A428 src/func_8007A404.c
0x8007C4EC 0x8007C524 src/func_8007C4EC.c
0x8007DC40 0x8007DC4C src/func_8007DC40.c
@@ -164,6 +167,7 @@
0x80099A94 0x80099AE4 src/func_80099A94.c
0x80099E14 0x80099E34 src/func_80099E14.c
0x8009AC08 0x8009AC28 src/func_8009AC08.c
0x8009B464 0x8009B4A0 src/func_8009B464.c
0x8009D8A0 0x8009D8E0 src/func_8009D8A0.c
0x8009E8D0 0x8009E95C src/func_8009E8D0.c
0x8009F0E8 0x8009F120 src/func_8009F0E8.c
@@ -172,6 +176,7 @@
0x800A6268 0x800A6294 src/func_800A6268.c
0x800A74BC 0x800A74D0 src/func_800A74BC.c
0x800A8B48 0x800A8B8C src/func_800A8B48.c
0x800A9D58 0x800A9D90 src/func_800A9D58.c
0x800AA56C 0x800AA59C src/func_800AA56C.c
0x800AC818 0x800AC85C src/func_800AC818.c
0x800AC85C 0x800AC884 src/func_800AC85C.c
@@ -222,6 +227,7 @@
0x800F8F9C 0x800F8FC0 src/func_800F8F9C.c
0x800F8FE4 0x800F8FF8 src/func_800F8FE4.c maspsx=off
0x800F8FF8 0x800F9008 src/func_800F8FF8.c
0x800F9344 0x800F9380 src/func_800F9344.c
0x800FA960 0x800FA980 src/func_800FA960.c
0x800FB13C 0x800FB1BC src/func_800FB13C.c
0x800FB5D4 0x800FB5DC src/func_800FB5D4.c
1 # Code-region registry: one C region per matched function.
64 0x800276B0
65 0x800290D0
66 0x800290F0
67 0x8002C6EC
68 0x8002C7BC
69 0x8002C888
70 0x8002C894
96 0x80042D64
97 0x80043D8C
98 0x80044F58
99 0x80045388
100 0x800453C0
101 0x8004C060
102 0x8004C090
128 0x8006FA78
129 0x8007049C
130 0x80072BA8
131 0x800734A4
132 0x8007A404
133 0x8007C4EC
134 0x8007DC40
167 0x80099A94
168 0x80099E14
169 0x8009AC08
170 0x8009B464
171 0x8009D8A0
172 0x8009E8D0
173 0x8009F0E8
176 0x800A6268
177 0x800A74BC
178 0x800A8B48
179 0x800A9D58
180 0x800AA56C
181 0x800AC818
182 0x800AC85C
227 0x800F8F9C
228 0x800F8FE4
229 0x800F8FF8
230 0x800F9344
231 0x800FA960
232 0x800FB13C
233 0x800FB5D4
+1
View File
@@ -179,6 +179,7 @@ D_80122150 0x80122150 gp
D_80122154 0x80122154 gp
D_80122158 0x80122158 gp
D_8012215C 0x8012215C gp
D_80122160 0x80122160 gp
D_80122164 0x80122164 gp
D_80122170 0x80122170 gp
D_80122174 0x80122174 gp
1 # Symbol registry: absolute addresses for cross-references used by C regions.
179 D_80122154
180 D_80122158
181 D_8012215C
182 D_80122160
183 D_80122164
184 D_80122170
185 D_80122174
+46
View File
@@ -0,0 +1,46 @@
/*
* func_8002C6EC — 60 bytes at 0x8002C6EC..0x8002C728
*
* Framed routine: appends its argument to a global array indexed by an incrementing
* `gp`-relative counter, then calls a routine.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* lw v0,0x24c(gp) 8f82024c v0 = *(int *)(gp + 0x24c)
* sw ra,0x10(sp) afbf0010 save ra
* addiu v0,v0,0x1 24420001 v0 += 1
* sw v0,0x24c(gp) af82024c *(int *)(gp + 0x24c) = v0
* sll v0,v0,0x2 00021080 v0 *= 4
* lui at,0x8011 3c018011 \
* addu at,at,v0 00220821 / at = 0x80110000 + index * 4
* sw a0,-0xcfc(at) ac24f304 *(int *)(at - 0xcfc) = a0
* jal 0x8002c3f8 0c00b0fe call func_8002C3F8
* li a1,0x1 24050001 a1 = 1 (delay slot)
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* `0x24c(gp)` is a `gp`-relative access off gp 0x80121938, i.e. 0x80121B84, which the registry
* already carries as `D_80121B84` with the `gp` marker. The counter is **incremented first**
* and the array is then indexed by the incremented value, so this is a pre-increment append.
*
* The array store is the explicit indexed symbol form (`lui at,%hi` / `addu at,at,index` /
* `sw rt,%lo(at)`), and the address arithmetic carries: `lui 0x8011` with the signed
* displacement -0xcfc gives **0x8010F304**, not 0x8011F304.
*
* LIMITS: the function name, the callee, the array and the counter's meaning are hypotheses;
* only the bytes are evidence. The array elements and the counter are 32-bit. The second
* argument to the callee is the literal 1, materialised in the `jal` delay slot.
*/
extern int D_80121B84;
extern int D_8010F304[];
extern void func_8002C3F8(int a0, int a1);
void func_8002C6EC(int a0)
{
D_80121B84++;
D_8010F304[D_80121B84] = a0;
func_8002C3F8(a0, 1);
}
+50
View File
@@ -0,0 +1,50 @@
/*
* func_80045388 — 56 bytes at 0x80045388..0x800453C0
*
* Framed routine guarded by a byte flag: when the flag is clear it calls one routine with a
* global pointer and its own argument.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* lui v0,0x8012 3c028012 \
* lbu v0,0x2374(v0) 90422374 / v0 = *(unsigned char *)0x80122374
* move a1,a0 00802821 a1 = a0
* bne v0,zero,0x800453b0 14400004 if (v0 != 0) goto epilogue
* sw ra,0x10(sp) afbf0010 save ra (delay slot)
* lui a0,0x8013 3c048013 \
* lw a0,-0x2774(a0) 8c84d88c / a0 = *(int *)0x8012D88C
* jal 0x8005a78c 0c0169e3 call func_8005A78C
* nop 00000000 (delay slot)
* 0x800453b0:
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* Byte-for-byte the same shape as func_800453C0 except for the callee (func_8005A78C here,
* func_8005A81C there) — the pair is one guard reached through two different routines. The
* difference between the two is only scheduling: here the frame is established **first** and
* the flag load second, in func_800453C0 the flag load is hoisted above the frame. Both come
* from the same C and are cc1's scheduling choice.
*
* The guard's `sw ra` sits in the branch delay slot, so `ra` is only saved on the path that
* reaches the call. The argument moves to a1 before a0 is overwritten with the global, so the
* call is `f(global, arg)`. The address arithmetic carries: `lui 0x8013` with the signed
* displacement -0x2774 gives **0x8012D88C**.
*
* LIMITS: the function name, the flag's meaning, the global's type and the callee are
* hypotheses; only the bytes are evidence. The flag is a byte (`lbu`) and the global is read
* as a 32-bit pointer. The routine sets no result, so it is `void`.
*/
extern unsigned char D_80122374;
extern int D_8012D88C;
extern void func_8005A78C(int a0, int a1);
void func_80045388(int a0)
{
unsigned char v0 = D_80122374;
if (v0 == 0)
func_8005A78C(D_8012D88C, a0);
}
+46
View File
@@ -0,0 +1,46 @@
/*
* func_800734A4 — 56 bytes at 0x800734A4..0x800734DC
*
* Framed routine: sets one bit of a 16-bit value, passes it on, and if the result is
* non-null passes that on too.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* sw ra,0x10(sp) afbf0010 save ra
* ori a0,a0,0x4000 34844000 a0 |= 0x4000
* sll a0,a0,0x10 00042400 a0 <<= 16
* jal 0x80072d0c 0c01cb43 call func_80072D0C
* sra a0,a0,0x10 00042403 a0 = (short)a0 (delay slot)
* beq v0,zero,0x800734cc 10400003 if (v0 == 0) goto epilogue
* nop 00000000 (delay slot)
* jal 0x8006f28c 0c01bcA3 call func_8006F28C
* move a0,v0 00402021 a0 = v0 (delay slot)
* 0x800734cc:
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* The `ori`/`sll`/`sra` triple is the mask-and-sign-extend this ABI applies to a `short`
* argument: bit 14 is set on the incoming value and the result is narrowed back to 16 bits
* before the call, so both the parameter and the callee's parameter are `short`. The
* narrowing is scheduled into the `jal` delay slot.
*
* The second call is guarded and receives the first call's result; nothing touches v0 after
* it, so the wrapper sets no result of its own and is `void`.
*
* LIMITS: the function names, the callees and the meaning of bit 14 are hypotheses; only the
* bytes are evidence. The `nop` in the first branch's delay slot means nothing was available
* to fill it.
*/
extern int func_80072D0C(short a0);
extern void func_8006F28C(int a0);
void func_800734A4(short a0)
{
int v0 = func_80072D0C(a0 | 0x4000);
if (v0 != 0)
func_8006F28C(v0);
}
+44
View File
@@ -0,0 +1,44 @@
/*
* func_8009B464 — 60 bytes at 0x8009B464..0x8009B4A0
*
* Framed routine: calls one routine with an advanced pointer, its own argument, a value
* selected by one bit of a field, and a zero.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* move a1,a0 00802821 a1 = a0
* addiu a0,a1,0x30 24a40030 a0 = a1 + 0x30
* sw ra,0x10(sp) afbf0010 save ra
* lw a2,0x28(a1) 8ca20028 a2 = *(int *)(a1 + 0x28)
* addu a3,zero,zero 00003821 a3 = 0
* andi a2,a2,0x8000 30428000 a2 &= 0x8000
* sltu a2,zero,a2 0002102b a2 = (0 < a2)
* subu a2,zero,a2 00021023 a2 = -a2 (0 or -1)
* jal 0x8009b074 0c026c1d call func_8009B074
* andi a2,a2,0x29a 3042029a a2 &= 0x29a (delay slot) (0 or 0x29a)
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* The four-instruction `andi`/`sltu`/`subu`/`andi` sequence is cc1's **if-conversion** of a
* two-constant conditional: `(field & 0x8000) ? 0x29a : 0` becomes
* `-((field & 0x8000) != 0) & 0x29a`, with the final `andi` scheduled into the `jal` delay
* slot. That is the same mechanism cookbook finding 26's neighbours show, and it is why the
* source is written as a ternary: an `if`/`else` assigning the same variable produces the same
* code.
*
* The first argument is the incoming pointer advanced by 0x30 (computed in a register copy, so
* the original value survives as the second argument), and a3 is zeroed with
* `addu rd,zero,zero`.
*
* LIMITS: the function name, the callee, the field at +0x28, the bit 15 test and the constant
* 0x29a are hypotheses; only the bytes are evidence. The field load is 32-bit.
*/
extern void func_8009B074(int a0, int a1, int a2, int a3);
void func_8009B464(int a0)
{
func_8009B074(a0 + 0x30, a0, (*(int *)(a0 + 0x28) & 0x8000) ? 0x29a : 0, 0);
}
+49
View File
@@ -0,0 +1,49 @@
/*
* func_800A9D58 — 56 bytes at 0x800A9D58..0x800A9D90
*
* Framed routine: calls one routine, and if it returns non-null passes the result on and
* then calls a second routine.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* sw ra,0x10(sp) afbf0010 save ra
* jal 0x800a82d0 0c02a0b4 call func_800A82D0
* nop 00000000 (delay slot)
* beq v0,zero,0x800a9d80 10400005 if (v0 == 0) goto epilogue
* nop 00000000 (delay slot)
* jal 0x800a9d90 0c02a764 call func_800A9D90
* move a0,v0 00402021 a0 = v0 (delay slot)
* jal 0x800a8224 0c02a089 call func_800A8224
* nop 00000000 (delay slot)
* 0x800a9d80:
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* Both calls are inside the guard: the first takes the tested result as its argument (moved
* into a0 in the `jal` delay slot), the second takes none. Nothing touches v0 after the
* second call, so the wrapper sets no result and is `void`.
*
* The first callee, 0x800A82D0, is one of the project's recorded open negatives
* (`near_match_negatives.tsv`, class `-`); it is referenced here as an unresolved symbol, not
* as a matched region. The second callee, 0x800A9D90, is the address immediately after this
* function's end.
*
* LIMITS: the function names and the callees' purposes are hypotheses; only the bytes are
* evidence. The guard tests v0 for zero (`beq v0,zero`), so the source condition is `!= 0`.
*/
extern int func_800A82D0(void);
extern void func_800A9D90(int a0);
extern void func_800A8224(void);
void func_800A9D58(void)
{
int v0 = func_800A82D0();
if (v0 != 0) {
func_800A9D90(v0);
func_800A8224();
}
}
+47
View File
@@ -0,0 +1,47 @@
/*
* func_800F9344 — 60 bytes at 0x800F9344..0x800F9380
*
* Framed routine: applies a routine to a 12-bit field of its argument, negating both the
* argument and the result when the argument is negative.
*
* The observed instructions are:
* addiu sp,sp,-0x18 27bdffe8 frame, 24 bytes
* bltz a0,0x800f9360 04800006 if (a0 < 0) goto the negative path
* sw ra,0x10(sp) afbf0010 save ra (delay slot)
* jal 0x800f9380 0c03e4e0 call func_800F9380
* andi a0,a0,0xfff 30840fff a0 &= 0xfff (delay slot)
* j 0x800f9370 081003dc goto epilogue
* nop 00000000 (delay slot)
* 0x800f9360:
* subu a0,zero,a0 00042023 a0 = -a0
* jal 0x800f9380 0c03e4e0 call func_800F9380
* andi a0,a0,0xfff 30840fff a0 &= 0xfff (delay slot)
* subu v0,zero,v0 00021023 v0 = -v0
* 0x800f9370:
* lw ra,0x10(sp) 8fbf0010 restore ra
* addiu sp,sp,0x18 27bd0018 frame release
* jr ra 03e00008
* nop 00000000 (delay slot)
*
* The two arms each call the same routine with the argument masked to 12 bits; the negative
* arm negates the argument first and the result afterwards. The positive arm ends with a `j`
* over the negative block, so the source is the early `return` for the negative case followed
* by the positive one — the layout is the branch target being the later block, which is the
* shape the `if (a0 < 0) return ...;` spelling produces here.
*
* Both masks are scheduled into their `jal` delay slots, and the guard's `sw ra` is in the
* `bltz` delay slot.
*
* LIMITS: the function name, the callee and the claim that the mask is a 12-bit field are
* hypotheses; only the bytes are evidence. The negation implies a signed result.
*/
extern int func_800F9380(int a0);
int func_800F9344(int a0)
{
if (a0 < 0)
return -func_800F9380((-a0) & 0xfff);
return func_800F9380(a0 & 0xfff);
}