phase9: merge C 4 — 365 regions / 356 distinct bodies

4 tier-2 frames (0x8002864C, 0x80049298 with gp=-D_80121BFC, 0x801032D4,
0x800893E8). C's process-error owning (hardcoded ends instead of the
worklist column) and the F24 finding (caller-saved reloaded pointer across
a call means the store belongs before the call) recorded. Rare-epilogue
census: 47 tier-2 rows carry the pattern at their final instructions —
definitive class, broadcast to the workers. Gate MATCH whole-binary
SHA-1 e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
Christopher Williams
2026-09-24 02:02:12 -04:00
parent 942beee61c
commit af0ac5f3b8
5 changed files with 192 additions and 0 deletions
+4
View File
@@ -75,6 +75,7 @@
0x80026F14 0x80026F3C src/func_80026F14.c
0x800276B0 0x800276D4 src/func_800276B0.c
0x800281A4 0x800281E4 src/func_800281A4.c
0x8002864C 0x80028698 src/func_8002864C.c
0x800290D0 0x800290F0 src/func_800290D0.c
0x800290F0 0x80029118 src/func_800290F0.c
0x8002A9D4 0x8002AA18 src/func_8002A9D4.c
@@ -129,6 +130,7 @@
0x800450C4 0x80045110 src/func_800450C4.c gp=-D_80121BFC
0x80045388 0x800453C0 src/func_80045388.c
0x800453C0 0x800453F8 src/func_800453C0.c
0x80049298 0x800492E4 src/func_80049298.c gp=-D_80121BFC
0x8004C060 0x8004C090 src/func_8004C060.c
0x8004C090 0x8004C0AC src/func_8004C090.c
0x8004C0AC 0x8004C0F0 src/func_8004C0AC.c
@@ -188,6 +190,7 @@
0x8008352C 0x8008355C src/func_8008352C.c
0x80085B80 0x80085B90 src/func_80085B80.c
0x80089314 0x80089338 src/func_80089314.c
0x800893E8 0x80089434 src/func_800893E8.c
0x80089C4C 0x80089C54 src/func_80042088.c
0x80089C54 0x80089C64 src/func_80089C54.c
0x80089C64 0x80089C74 src/func_80089C64.c
@@ -329,6 +332,7 @@
0x80102B30 0x80102B5C src/func_80102B30.c maspsx=off
0x80102FA4 0x80102FD4 src/func_80102FA4.c
0x80102FD4 0x80102FE0 src/func_80102FD4.c
0x801032D4 0x80103320 src/func_801032D4.c
0x80103A94 0x80103AA0 src/func_80103A94.c
0x80103B54 0x80103B60 src/func_80103B54.c
0x80103B60 0x80103B6C src/func_80103B60.c
1 # Code-region registry: one C region per matched function.
75 0x80026F14
76 0x800276B0
77 0x800281A4
78 0x8002864C
79 0x800290D0
80 0x800290F0
81 0x8002A9D4
130 0x800450C4
131 0x80045388
132 0x800453C0
133 0x80049298
134 0x8004C060
135 0x8004C090
136 0x8004C0AC
190 0x8008352C
191 0x80085B80
192 0x80089314
193 0x800893E8
194 0x80089C4C
195 0x80089C54
196 0x80089C64
332 0x80102B30
333 0x80102FA4
334 0x80102FD4
335 0x801032D4
336 0x80103A94
337 0x80103B54
338 0x80103B60
+44
View File
@@ -0,0 +1,44 @@
/*
* func_8002864C — 76 bytes at 0x8002864C..0x800286A0
*
* Two-argument wrapper with a scratch buffer: fills a 16-byte local buffer, hands
* it and the two caller arguments to a second routine, and returns 1. Both
* caller arguments are kept in callee-saved registers across the first call.
*
* The observed instructions are:
* addiu sp,sp,-48
* sw s0,32(sp)
* move s0,a1 ; s0 = first caller argument
* sw s1,36(sp)
* move s1,a2 ; s1 = second caller argument
* sw ra,40(sp)
* jal 0x80010B14
* addiu a1,sp,16 ; second argument = the buffer (delay slot)
* addiu a0,sp,16 ; first argument = the buffer
* move a1,s0
* jal 0x800283F4
* move a2,s1 ; third argument (delay slot)
* li v0,1 ; return 1
* lw ra,40(sp)
* lw s1,36(sp)
* lw s0,32(sp)
* addiu sp,sp,48
* jr ra
* nop
*
* The 48-byte frame holds a 16-byte buffer at sp+16 plus the two saved registers
* and `ra`; the buffer is addressed as `sp + 16`, which is what a 16-byte local
* array produces in this frame.
*
* LIMITS: the buffer size (16) and the two callees are hypotheses read from the
* instruction shape; what the buffer and the callees mean is unknown and is not
* guessed here. Only the compiled bytes are evidence.
*/
int func_8002864C(char *a0, int a1, int a2) {
int buf[4];
func_80010B14(a0, buf);
func_800283F4(buf, a1, a2);
return 1;
}
+46
View File
@@ -0,0 +1,46 @@
/*
* func_80049298 — 76 bytes at 0x80049298..0x800492EC
*
* Indexes a 76-byte-stride record table, reads a signed 16-bit field out of it,
* and makes two calls. The stride is `cc1`'s strength reduction of `* 76` into
* `*5`, `*4`, `-self`, `*4`.
*
* The observed instructions are:
* addiu sp,sp,-24
* sll v0,a0,0x2 ; index * 4
* addu v0,v0,a0 ; index * 5
* sll v0,v0,0x2 ; index * 20
* subu v0,v0,a0 ; index * 19
* lui v1,0x8012
* lw v1,7164(v1) ; v1 = D_80121BFC (the record table base)
* sll v0,v0,0x2 ; index * 76
* sw ra,16(sp)
* addu v0,v0,v1 ; table + index*76 (index first)
* lh a0,74(v0) ; *(short *)(record + 74) <- SIGNED 16-bit
* jal 0x800909D8
* move a1,zero ; second argument = 0 (delay slot)
* jal 0x800ACA10
* nop
* lw ra,16(sp)
* addiu sp,sp,24
* jr ra
* nop
*
* This is the sibling of the MATCHED func_800450C4: same table base, same stride,
* same direct-expression `addu` order. **D_80121BFC is gp-marked in the tracked
* registry but read ABSOLUTELY here**, so this region needs the per-region
* `gp=-D_80121BFC` override (cookbook finding 16, the per-SITE rule).
*
* LIMITS: the table base (0x80121BFC), the stride (76), the field offset (74) and
* the callees are hypotheses read from the instruction shape; what the records
* hold is unknown and is not guessed here. Only the compiled bytes are evidence.
*/
extern int D_80121BFC;
void func_80049298(int index) {
char *record = (char *)(index * 76 + D_80121BFC);
func_800909D8(*(short *)(record + 74), 0);
func_800ACA10();
}
+51
View File
@@ -0,0 +1,51 @@
/*
* func_800893E8 — 76 bytes at 0x800893E8..0x8008943C
*
* Extracts a signed 4-bit field out of a word reached through two pointer hops,
* uses it to index a table of words and writes -1 there, then re-reads the first
* hop and clears a field on it before a call.
*
* The observed instructions are:
* addiu sp,sp,-24
* sw ra,16(sp)
* lw v0,28(a0) ; q = p->ptr_1c
* nop
* lw v0,12(v0) ; q->word_0c
* li v1,-1
* sll v0,v0,0x14 ; << 20
* sra v0,v0,0x1c ; >> 28 <- ARITHMETIC, so a SIGNED 4-bit field
* sll v0,v0,0x2 ; * 4
* lui at,0x8014
* addu at,at,v0 ; table + field*4
* sw v1,-31648(at) ; D_80138460[field] = -1 (%lo as displacement)
* lw v0,28(a0) ; RELOAD q = p->ptr_1c
* jal 0x80089314
* sw zero,8(v0) ; q->word_08 = 0 (delay slot)
* lw ra,16(sp)
* addiu sp,sp,24
* jr ra
* nop
*
* The `sll`/`sra` PAIR is the tell that the field is a signed bitfield: a plain
* `(x >> 8) & 0xf` would emit `srl`/`andi`. The shift pair is therefore written
* explicitly rather than as a mask. The pointer is loaded twice, so the C re-reads
* it rather than caching it.
*
* LIMITS: the pointer offsets (0x1c, 0x0c, 0x08), the table base (0x80138460) and
* the bitfield position (bits 8-11, signed) are hypotheses read from the
* instruction shape; what the object and the table mean is unknown and is not
* guessed here. Only the compiled bytes are evidence.
*/
extern int D_80138460[];
void func_800893E8(char *p) {
char *q = *(char **)(p + 28);
int field = (*(int *)(q + 12) << 20) >> 28;
D_80138460[field] = -1;
q = *(char **)(p + 28);
*(int *)(q + 8) = 0;
func_80089314();
}
+47
View File
@@ -0,0 +1,47 @@
/*
* func_801032D4 — 76 bytes at 0x801032D4..0x80103328
*
* GTE state reset: one no-argument call, the far-colour triple zeroed, the
* OFX/OFY pair zeroed, then two adjacent 16-bit globals cleared with absolute
* stores.
*
* The observed instructions are:
* addiu sp,sp,-24
* sw ra,16(sp)
* jal 0x801097A0
* nop
* move a0,zero
* move a1,zero
* jal 0x80103B6C ; gte_ldRFC / gte_ldGFC / gte_ldBFC
* move a2,zero ; all three zero (delay slot)
* move a0,zero
* jal 0x80109778 ; gte_ldOFX / gte_ldOFY
* move a1,zero ; both zero (delay slot)
* lui at,0x8014
* sh zero,11812(at) ; D_80142E24 = 0
* lui at,0x8014
* sh zero,11808(at) ; D_80142E20 = 0
* lw ra,16(sp)
* addiu sp,sp,24
* jr ra
* nop
*
* The two final stores are ABSOLUTE (through `$at`), not gp-relative, so the two
* symbols must NOT be gp-marked: `lui 0x8014` plus 11812/11808 gives 0x80142E24
* and 0x80142E20.
*
* LIMITS: the two global addresses and the three callees are hypotheses read from
* the instruction shape; what the state means is unknown and is not guessed here.
* Only the compiled bytes are evidence.
*/
extern short D_80142E24;
extern short D_80142E20;
void func_801032D4(void) {
func_801097A0();
func_80103B6C(0, 0, 0);
func_80109778(0, 0);
D_80142E24 = 0;
D_80142E20 = 0;
}