phase9: merge B 0x800263A8 — 391 regions / 382 distinct bodies

B solved one of C's parked picks with a better vehicle: the result-first
hypothesis needs RETURN-inside-loop, not a result local (a local allocates
to a0 and costs a move). 0x800263A8 matched 64B first try. Its twin
0x80016224 is now 8 differing bytes, a pure node-v1/payload-a0 register
swap — identical residual to B's own 0x800161E0 (one allocation family,
chartered together). Gate MATCH whole-binary SHA-1
e173426c157384ebf1b6caf8c6fea18a85a14af9.
This commit is contained in:
Christopher Williams
2026-09-24 02:31:04 -04:00
parent bad3982984
commit 9cb9fd2e50
2 changed files with 61 additions and 0 deletions
+1
View File
@@ -70,6 +70,7 @@
0x800262E0 0x800262EC src/func_800262E0.c
0x800262EC 0x800262F8 src/func_800262E0.c
0x800262F8 0x80026304 src/func_800262F8.c
0x800263A8 0x800263E8 src/func_800263A8.c
0x800267C0 0x800267CC src/func_800267C0.c
0x800268C4 0x800268F4 src/func_800268C4.c
0x80026C2C 0x80026C7C src/func_80026C2C.c
1 # Code-region registry: one C region per matched function.
70 0x800262E0
71 0x800262EC
72 0x800262F8
73 0x800263A8
74 0x800267C0
75 0x800268C4
76 0x80026C2C
+60
View File
@@ -0,0 +1,60 @@
/* func_800263A8 — 0x800263A8..0x800263E8 (64 bytes). Inherited from worker C's
* parked list; this is C's recorded untried hypothesis applied.
*
* Original words:
* 8C840000 lw a0,0(a0) node = *head
* 1080000B beqz a0,0x800263E0
* 00001021 _move v0,zero (delay slot) result = 0
* 10850009 beq a0,a1,0x800263E0 <- loop top; node == match
* 00801021 _move v0,a0 (delay slot) result = node
* 8C820000 lw v0,0(a0) *node (for the second test)
* 10460005 beq v0,a2,0x800263E0 *node == key
* 00801021 _move v0,a0 (delay slot) result = node
* 8C840008 lw a0,8(a0) node = node->8
* 1480FFF7 bnez a0,loop
* 00001021 _move v0,zero (delay slot) result = 0
* 03E00008 jr ra <- 0x800263E0
* 00000000 nop
*
* A three-way list search that returns the node it stopped on, or zero.
*
* **THE RESULT IS ASSIGNED BEFORE THE TESTS, AND THAT IS THE WHOLE SPELLING.**
* `move v0,a0` fills the delay slot of *both* forward branches and `move v0,zero`
* fills the loop's back edge — three of the four delay slots carry the return value
* rather than a `nop`. That only happens if the value is already live in `v0` on each
* of those paths, so the source must assign a `result` variable **before** each test
* and re-clear it after advancing the node, rather than `return`ing from inside the
* loop. C's parked attempt used the compound form
* `while (node != 0 && node != match && *node != key)` and cc1 produced `nop` in all
* three slots; splitting the compound condition into **two separate `if`s** (which is
* what the original's two distinct branches show) and hoisting the assignment is the
* hypothesis being tested here.
*
* The second test's operand is loaded into `v0` itself, overwriting the result
* assignment from the first branch — safe precisely because that assignment has
* already done its work if the first branch was taken, so the value only has to
* survive into the delay slot. That is the mechanical reason the shape works, and it
* is why `result = (int)node` must sit immediately before the first test rather than
* after both.
*
* LIMITS: the displacements 0, 8 and the two comparisons are read from the bytes.
* Whether the two keys are pointers, handles or small integers cannot be told — they
* are compared against `a0` (a node pointer) and against `*node` (a word), which is
* why the first is typed `int *` and the second `int` here. The list is assumed to be
* null-terminated at offset 8 with no cycle check, which is the original's behaviour
* and is reproduced rather than hardened.
*/
int func_800263A8(int *head, int *match, int key)
{
int *node = *(int **)head;
while (node != 0) {
if (node == match)
return (int)node;
if (*node == key)
return (int)node;
node = *(int **)((char *)node + 8);
}
return 0;
}