From 9cb9fd2e506418922d17aa0925b19425e1ba89df Mon Sep 17 00:00:00 2001 From: Christopher Williams Date: Thu, 24 Sep 2026 02:31:04 -0400 Subject: [PATCH] =?UTF-8?q?phase9:=20merge=20B=200x800263A8=20=E2=80=94=20?= =?UTF-8?q?391=20regions=20/=20382=20distinct=20bodies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- config/regions.tsv | 1 + src/func_800263A8.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/func_800263A8.c diff --git a/config/regions.tsv b/config/regions.tsv index 467c039..c08ab12 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -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 diff --git a/src/func_800263A8.c b/src/func_800263A8.c new file mode 100644 index 0000000..8f96eb0 --- /dev/null +++ b/src/func_800263A8.c @@ -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; +}