feat(phase-30 S48-T6): recover all 21 "lost" wave-2 drafts from the transcripts — 17 more banked

Drew's question ("can you just analyze the workflow results to get those
drafts back?") was right, and my write-off was wrong. The drafts were never
lost: every agent's tool calls are recorded in the run transcripts, content
included. Recovery is deterministic and cost ~0 agent tokens.

Method (all three passes were needed):
1. Write records -> 20 of 21 had one. Naive extraction gated only 8/21,
   because agents REFINE with Edit and I was treating each edit's new_string
   as a whole file.
2. Replay Write-then-Edit in order per (agent, file_path), snapshotting after
   every mutation, then gate every snapshot newest-first -> 20/21 MATCH.
3. The last one (func_8017DF40) never used Write/Edit — it wrote via a shell
   heredoc. Extracted the heredoc bodies from the bash tool calls -> MATCH.

Whole-binary gate on the 21: 17 BANKED, 4 NEAR.
  md_SC03_073 func_801EFC94 x8   <- a MODULE exemplar, through the path fixed
                                    earlier today (commit:1626)
  ov_SC03_014 func_8017C154 x7  func_8017C6A0 x7  func_8017D1E0 x7
  ov_SC03_118 func_80187180 x8  func_80187B80 x8
  ov_SC06_018 func_80185C2C func_8018DE60 func_801850F4 func_801857CC
              func_801880C4 func_80185DD8 (all x6)
  ov_MAIN_012 func_8017DD28 x5 · ov_SC02_026 func_801814D8 x6
  ov_SC03_093 func_8018171C x5 · ov_SC03_107 func_8017EB70 x5
  ov_SC06_008 func_80180000 x8
NEAR at the binary gate: func_8017DF40, func_8017EEEC, func_80187960,
func_8018A974 — the §52b population (per-function MATCH, binary gate refuses).

Wave 2 now stands at 22 of 28 banked (79%) vs wave 1's 8 of 12 (67%), with
20 of 28 drafted by Sonnet.
This commit is contained in:
Drew T
2026-08-11 20:56:31 -06:00
parent 0ec7d4c052
commit 95909749bb
15 changed files with 1344 additions and 23 deletions
+48 -1
View File
@@ -273,7 +273,54 @@ void func_801EFBF4(s32 a0) {
}
INCLUDE_ASM("asm/md_SC03_073/nonmatchings/md_SC03_073", func_801EFC94);
#include "common.h"
extern s32 func_801789AC(s32 arg0);
extern void func_80188F20(s32 a0);
extern void func_80178CBC(s32 a0, s32 a1);
extern void func_80174438(s32 a0);
extern u8 *D_80126B10;
void func_801EFC94(void *a0) {
extern s32 D_801EFFF8;
extern s32 D_801F0010;
extern s32 D_801EFF94;
switch (*(u16 *)((s32)a0 + 0x34)) {
case 0: {
s32 v0 = func_801789AC((s32)a0);
switch (v0) {
case 1:
*(u16 *)((s32)a0 + 0x34) = 2;
func_80188F20(3);
break;
case 2:
func_80178CBC((s32)a0, (s32)&D_801EFFF8);
*(u16 *)((s32)a0 + 0x34) = 0;
break;
case 3:
func_80178CBC((s32)a0, (s32)&D_801F0010);
*(u16 *)((s32)a0 + 0x34) = 3;
break;
}
break;
}
case 1:
break;
case 2:
func_80178CBC((s32)a0, (s32)&D_801EFF94);
*(u16 *)((s32)a0 + 0x34) = 0;
break;
case 3:
if (func_801789AC((s32)a0) != 0) {
func_80174438((s32)D_80126B10);
*(u16 *)((s32)a0 + 0x34) = 1;
}
break;
}
}
extern void func_8012C1B8(void);
extern void func_8012CAE4(void *a0);
+129 -1
View File
@@ -4225,7 +4225,135 @@ u32 func_8017DC48(s32 a0, s32 a1) {
INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DCB0);
INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DD28);
#include "common.h"
/* func_8017DD28 @ 0x8017DD28 — ov_MAIN_012 / jr_8017CF3C, 124 ins, frame 0x30.
* Family exemplar (reach x5, zero prior cracks).
*
* WHAT IT DOES. Fills one 0x14-byte SPRT (tag 0x04000000, rgb/code 0x64808080,
* u0/v0 = 0x70/0x10, clut 0x4056, w/h = 0x10/0x10) whose x/y come from the
* current HUD panel's Prim4 (D_80115134[D_8011511A].f18), offset by a table
* value when D_8011512C == 1. Links it into the OT with the psyq addPrim
* idiom, advances past it, has func_8005A600 (SetDrawTPage-shaped, 2 words)
* write the next primitive, links THAT one too, and returns the write cursor.
*
* STEP-0 SIBLING (cookbook §160g) — the whole prim fill + the PTag bitfield
* addPrim were copy-edited from the already-banked, SAME-OVERLAY
* src/ov_MAIN_012/ov_MAIN_012_jr_8013F350.c:1746 func_80140D68
* which has the identical 0x04000000 / 0x70 / 0x10 / 0x64808080 / 0x4056 /
* 0x10 / 0x10 store sequence and the identical
* ((PTag *)out)->addr = ((PTag *)(D_800AE7BC[*pb].ot + 2))->addr;
* ((PTag *)(D_800AE7BC[*pb].ot + 2))->addr = (u32)out;
* pair. Only the 24-bit-bitfield spelling emits exactly two `and`s per half.
*
* THE THREE LEVERS (each byte-measured with tools/match_one.py):
*
* [L1] `out += 5;` IN PLACE, never `p = out + 5;`. A second pointer local is
* a 5th callee-saved allocno: frame stays 0x30 but the target's four
* ($s0..$s3) become five ($s0..$s4) and every save/restore shifts.
* 125 ins / 115 mismatched -> 123 / 33.
*
* [L2] `d = n - 0x60;` INTO ITS OWN LOCAL, then `q->f0 + d`. Writing the
* obvious `q->f0 + (n - 0x60)` lets fold reassociate the constant onto
* the OTHER addend — `addiu $v0,$v0,-0x60` on the lhu result — and
* writing `n -= 0x60;` makes it a single pseudo, so the subtract is
* in-place (`addiu $a0,$a0,-0x60`) and floats up ~10 slots because its
* destination is free early. Only a distinct, single-set pseudo gives
* the target's `addiu $v1,$a0,-0x60`, which cannot be scheduled before
* `sw $v1,0x4($s3)` frees $v1 — and that one anchor pins the whole
* lui/ori/li/move ordering of the fill block. 26 mismatched -> 16.
*
* [L3] The LAST addPrim write-half must keep its loaded word in $v0 through
* the `or`, so the return value `addiu $v0,$s3,0x8` cannot be scheduled
* into the load-delay slot. With the plain bitfield spelling gcc puts
* that word in $v1/$a0, $v0 falls free, sched2 hoists the return insn
* into the slot, and the target's `nop` after `lw $v1,%lo(D_800AE7BC)`
* disappears — a LENGTH-DRIFT of exactly -1 that no amount of statement
* reordering fixes. `register u32 v __asm__("$2")`, REUSED for the
* or-result, is the only lever that holds it. 16 mismatched -> MATCH.
* (Ablated: pinning `op` to $3 and `pb` to $18 are NOT needed once [L3]
* is in; both were removed and the gate still reads MATCH.)
*
* §94 TYPE-CARRY: every typedef here is BLOCK-scope on purpose — extract_unit
* carries file-scope externs but drops file-scope typedefs, so the four
* mechanical siblings would sweep 0/4 if these lived at file scope.
*/
s32 *func_8017DD28(s32 *out) {
typedef struct { u32 addr : 24; u32 len : 8; } PTag_8017DD28;
typedef struct { u32 *ot; u32 pad[4]; } Env_8017DD28; /* 0x14 stride */
typedef struct { u16 f0; u16 f2; } Prim4_8017DD28;
typedef struct {
s16 f0; /* 0x00 */
s16 f2; /* 0x02 */
void *f4; /* 0x04 */
void *f8; /* 0x08 */
s16 fC; /* 0x0C */
s16 fE; /* 0x0E */
s16 f10; /* 0x10 */
s16 f12; /* 0x12 */
void *f14; /* 0x14 */
Prim4_8017DD28 *f18; /* 0x18 */
void *f1C; /* 0x1C */
} Panel_8017DD28; /* 0x20 stride */
extern Env_8017DD28 D_800AE7BC[];
extern short D_800B9A02;
extern Panel_8017DD28 *D_80115134;
extern u16 D_8011511A;
extern s16 D_8011512C;
extern u16 D_80115116;
extern u16 D_80182798[];
extern s32 func_8005A600(s32, s32, s32, s32, s32);
Prim4_8017DD28 *q;
volatile u16 *pb;
s32 n;
s32 d;
/* `lh` on a u16-declared symbol: the address cast, not a second decl —
the TU already fixes D_8011511A as u16 at file scope. */
q = D_80115134[*(s16 *)&D_8011511A].f18;
if (D_8011512C == 1) {
n = D_80182798[D_80115116 & 7];
} else {
n = 0;
}
out[0] = 0x04000000;
*((u8 *)out + 0xC) = 0x70;
*((u8 *)out + 0xD) = 0x10;
out[1] = 0x64808080;
pb = (volatile u16 *)&D_800B9A02;
*(u16 *)((u8 *)out + 0xE) = 0x4056;
d = n - 0x60; /* [L2] */
*(s16 *)((u8 *)out + 0x8) = q->f0 + d;
*(s16 *)((u8 *)out + 0xA) = q->f2 - 2;
*(s16 *)((u8 *)out + 0x12) = 0x10;
*(s16 *)((u8 *)out + 0x10) = 0x10;
((PTag_8017DD28 *)out)->addr =
((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr;
((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr = (u32)out;
out += 5; /* [L1] */
func_8005A600((s32)out, 0, 0, 0x15, 0);
((PTag_8017DD28 *)out)->addr =
((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr;
{
u32 *op;
register u32 v __asm__("$2"); /* [L3] */
op = D_800AE7BC[*pb].ot;
v = op[2];
v = (v & 0xFF000000) | (((u32)out) & 0xFFFFFF);
op[2] = v;
}
return out + 2;
}
INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DF18);
+60 -1
View File
@@ -4558,7 +4558,66 @@ void func_80181374(s32 a0) {
INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_8018144C);
INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_801814D8);
extern s32 func_80182550(void);
extern void func_8012CAE4(void *a0);
extern s32 func_8012C354(s32 a0, s32 a1);
extern void func_8012E8A8(u8 *a0);
extern void func_8012B2CC(s32 a0);
extern s32 rand(void);
extern u8 D_801AC1D0[];
extern u8 D_801AC270[];
void func_801814D8(s32 a0) {
s16 state;
s16 flag;
s32 p;
s32 dst;
if ((*(u16 *)(a0 + 0x70) & 0xF) == 0 && func_80182550() == 0) {
func_8012CAE4((void *)a0);
return;
}
state = *(u16 *)(a0 + 0x70) & 0xF;
if (func_8012C354(a0, (s32)(D_801AC1D0 + state * 0x34)) == 0) {
return;
}
*(u8 *)(a0 + 0xC0) = 1;
*(s32 *)(a0 + 0xBC) = (s32)D_801AC270;
*(s32 *)(a0 + 0xB4) = -2;
*(s32 *)(a0 + 0xC4) |= 1;
*(s16 *)(a0 + 0xFE) = (rand() % 16) + 8;
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10;
flag = *(s16 *)(a0 + 0x70);
if ((flag & 0x8000) == 0) {
if ((flag & 0x800) != 0) {
*(s16 *)(a0 + 0x2) = 5;
func_8012E8A8((u8 *)a0);
} else {
*(s16 *)(a0 + 0x2) = 1;
}
} else {
p = *(s32 *)(a0 + 0x64);
*(s16 *)(a0 + 0x2) = 3;
*(s16 *)(a0 + 0x5C) = 0;
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) = *(u16 *)(*(s32 *)(p + 0x20) + 0x12);
dst = *(s32 *)(a0 + 0x20);
*(s16 *)(dst + 0x18) = *(s16 *)(dst + 0x1A) = *(s16 *)(dst + 0x1C) = 1;
func_8012B2CC(a0);
}
}
INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_80181644);
+250 -4
View File
@@ -3384,7 +3384,7 @@ void func_8017C0C8(void *a0) {
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C104);
extern void func_8017C154(void);
extern void func_8017C154();
void func_8017C12C(void) {
func_8017C154();
}
@@ -3392,7 +3392,39 @@ extern void func_8017C154(void);
DEFINE_func_8017C14C() /* dedup: shared engine-core @0x8017C14C (src/shared) */
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C154);
extern void func_80015978(s32 a0, s32 *a1);
extern void func_8017C290(int a, s16 *b, SVECTOR_8017C290 *c, SVECTOR_8017C290 *d,
SVECTOR_8017C290 *e, SVECTOR_8017C290 *f, s16 *g);
extern SVECTOR_8017C290 D_8018F038[4];
void func_8017C154(void *a0)
{
s16 buf20[4];
SVECTOR_8017C290 c;
SVECTOR_8017C290 d;
SVECTOR_8017C290 e;
SVECTOR_8017C290 f;
s32 i, j;
*(s16 *)((u8 *)a0 + 0x10) = *(s32 *)((u8 *)a0 + 0x30);
func_80015978((s32)a0 + 4, (s32 *)buf20);
for (j = 0; j < 4; j++) {
c.vx = 0;
c.vy = 0;
c.vz = 0;
d = c;
e = c;
for (i = 0; i < 4; i++) {
f = D_8018F038[i];
*(s16 *)((u8 *)a0 + 0x12) = i + j;
func_8017C290((int)a0, buf20, &c, &d, &e, &f, (s16 *)((u8 *)a0 + 0x10));
}
}
}
// @class: regalloc-order
// @stuck: none — §136c SIBLING-FIRST. Near-twin = banked func_8017E830 in
@@ -3540,7 +3572,115 @@ void func_8017C664(void *a0) {
}
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C6A0);
#include "common.h"
/* MATCH (match_one, 93/93). ov_SC03_014_jr_8017AE2C, family reach x7 (zero-crack exemplar; see
* asm/ov_SC03_0{14,15,24,118,119}/... and ov_SC06_000, all still INCLUDE_ASM as of this crack).
*
* sibling-search (cookbook §160g) hits, all from src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c
* (the destination TU itself) plus one cross-overlay MATCHed twin:
* - func_8017CE10(void *a0, s32 a1, s32 a2) -- defined verbatim in THIS TU (line 3679)
* - func_80147324(D_8018EFC0[idx][0]) -- exact idiom of func_8017C8FC's
* func_80147324(D_8018EFD4[idx][0]) (same TU)
* - func_8001CB00(s32,void*,s32,s32) -- signature + literal 0x280/0x100 pair pinned
* by src/ov_SC03_007/ov_SC03_007_jr_8017AE2C.c:5317 func_80186BE8 (labeled MATCH), whose tail
* `*(short*)(param_1+2) += 1;` is the exact idiom of this function's own final statement.
* - func_8012A68C()/func_8012A758()/func_8004978C()/ApplyMatrixSV() call trio -- exact shape of
* shared-engine func_80146F58 (src/ov_SC07_007/ov_SC07_007_jr_801457A4.c:1459): two s16 calls
* stored, func_8004978C(anglesPtr, matOut), ApplyMatrixSV(mat, in, out).
* - func_801465C0 loose void(void) file-scope decl (TU:130) fought via a cast-at-callsite,
* per §161c -- mirrors src/ov_SC06_008/ov_SC06_008_jr_8016AB6C.c's
* `((s32 (*)(void))func_801465C0)()` pattern. No explicit a0 setup precedes the target's jal
* (a0 still holds the entry parameter unclobbered) so a ZERO-ARG cast is the byte-safe choice
* -- it can never force a spurious argument-setup instruction.
*
* PROCESS NOTE (worth banking in the cookbook): a 2-instruction "REGALLOC-LOCAL" residual on
* func_80015954's args looked exactly like local-alloc's optimize_reg_copy_1 collapsing two
* identical-valued arg copies (byte-verified via `cc1 -da`: `.sched` had insn112/114 both reading
* pseudo 80 cleanly, `.lreg` had insn114 rewritten to read insn112's DEST instead of pseudo80's
* hard reg -- textbook §162j1). The `register s32 zr __asm__("$0"); x + zr` opaque-copy lever
* (§136d-1/RC-12) did NOT defeat it when applied to the SECOND of the pair (validate_replace_rtx
* substitutes inside a PLUS operand just as readily as inside a plain SET) -- applying it to the
* FIRST copy instead (so insn117 is no longer a `single_set(REG)` and never qualifies as "a copy"
* for the pass to scan forward from) did defeat it, dropping to a genuine 1-instruction
* REGALLOC-PERM ($s3-vs-$s0). That flushed out the REAL bug: `func_80015954`'s first argument is
* `vecOut` (the ApplyMatrixSV output), not `s3` -- I had the wrong VALUE, not a regalloc quirk.
* Fixing the argument made the "residual" vanish with NO register-pin needed at all. Lesson: a
* clean REGALLOC-LOCAL/-PERM diff on an ARGUMENT SETUP is worth re-deriving the argument's
* identity from the target's OWN register (here $s0, not the more "obvious" $s3) before reaching
* for §162j1/RC-12 levers -- they can mask a semantic error long enough to look load-bearing.
*/
extern void func_801465C0(void);
extern void func_80149374(s32 a0, s32 a1);
extern s16 func_8012A68C(void);
extern s16 func_8012A758(void);
extern void func_8004978C(s16 *a0, void *a1);
extern void ApplyMatrixSV(void *a0, void *a1, void *a2);
extern void func_80015978(s32 a0, s32 *a1);
extern void func_8012EF70(s32 a0, s32 a1);
extern void func_80015954(s32 a0, s32 a1);
extern void func_8001CB00(s32 a0, void *a1, s32 a2, s32 a3);
extern void func_8017CE10(void *a0, s32 a1, s32 a2);
extern void func_80147324(s32 a0);
extern void func_80146C3C(void);
/* new-to-this-TU data symbols (own address only in this function; payload owned by
* asm/ov_SC03_014/data/tail.data.s, a data-only splat unit -- extern is correct, not a definition,
* per §160c's "same .s as the function" test). D_8018F07C bytes: 0000 0000 ECFF 0000 = {0,0,-20,0}.
* D_8018F058: 12 opaque bytes (a GPU-primitive template), address-only use -> §160f array style. */
extern s16 D_8018F07C[4];
extern u8 D_8018F058[12];
extern u16 D_8018EFC0[][2];
void func_8017C6A0(void *a0) {
void *s3;
s32 s0;
s32 s1;
u8 mat[0x20];
u16 vecOut[4];
s0 = *(s32 *)(a0 + 0x34);
s3 = ((void *(*)(void))func_801465C0)();
*(void **)(a0 + 0x20) = s3;
if (s3 != NULL) {
s1 = (s32)a0 + 4;
func_80149374(s0, s1);
*(s16 *)(s3 + 0x10) = func_8012A68C();
*(s16 *)(s3 + 0x12) = func_8012A758();
func_8004978C((s16 *)(s3 + 0x10), mat);
ApplyMatrixSV(mat, D_8018F07C, vecOut);
*(u16 *)(a0 + 0x6) = *(u16 *)(a0 + 0x6) + vecOut[0];
*(u16 *)(a0 + 0xA) = *(u16 *)(a0 + 0xA) + vecOut[1];
*(u16 *)(a0 + 0xE) = *(u16 *)(a0 + 0xE) + vecOut[2];
func_80015978(s1, (s32 *)vecOut);
func_8012EF70((s32)vecOut, (s32)vecOut);
func_80015954((s32)vecOut, s1);
func_8001CB00((s32)s3, D_8018F058, 0x280, 0x100);
*(u8 *)(s3 + 0x27) = 0x80;
*(s16 *)(s3 + 0x2C) = *(u16 *)(a0 + 0xE);
*(s16 *)(s3 + 0x1A) = 0;
*(s16 *)(s3 + 0x18) = 0;
*(s32 *)(a0 + 0x10) = 0;
func_8017CE10(a0, *(s32 *)(a0 + 0x2C), 0x8F);
func_80147324(D_8018EFC0[*(s32 *)(a0 + 0x2C)][0]);
*(u16 *)(a0 + 2) = *(u16 *)(a0 + 2) + 1;
} else {
((void (*)(s32))func_80146C3C)((s32)a0);
}
}
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C814);
@@ -3718,7 +3858,113 @@ INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D11
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D194);
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D1E0);
/* func_8017D1E0 -- ov_SC03_014, TU ov_SC03_014_jr_8017AE2C.c
*
* §160g sibling-first: this TU's own func_8017D318 (defined a few lines below this
* function's INCLUDE_ASM site, same file) is func_8017D1E0's ONLY non-engine callee --
* it fixes the SVECTOR_8017C290 {u16 vx,vy,vz,pad;} type and func_8017D318's exact
* signature `(int a0, SVECTOR_8017C290 *a1, SVECTOR_8017C290 *a2, s32 a3)` for free.
* The two locals `vec1`/`vec2` are that call's a1/a2: each stack SVECTOR gets vx=0,
* vy=the just-clamped position field, vz=1 (a constant -- see below).
*
* D_8018EFFC: same TU's func_8017C8FC has the identical idiom one page up --
* `idx = *(s32*)(a0+0x2C); func_80147324(D_8018EFD4[idx][0]);` against
* `extern u16 D_8018EFD4[][2];` at the SAME struct field offset (0x2C). D_8018EFFC
* sits 0x28 bytes after D_8018EFD4 in this overlay's rodata and is read with the
* identical `sll 2 / lhu [idx][0]` shape, so it is typed `u16[][2]` the same way.
* NOT independently verified against a byte dump of the table itself -- flag this
* decl for a second look if D_8018EFFC ever gets its own definition banked.
* (D_8018EFFC also exists as a DIFFERENT symbol -- a fn-ptr table -- in the
* unrelated overlay ov_SC03_001; overlays never share a TU, so no collision.)
*
* @class: regalloc-split (two REGISTER PINS, both load-bearing, neither a §17 tie)
* `t = field0x30 + 0x6000` feeds an accumulate BEFORE the func_80146E98 call and a
* second accumulate AFTER it. A plain `s32 t` (or even a `tmp`/`t` two-variable
* split) gets folded by cse/local-alloc into ONE pseudo living in $s1 for its WHOLE
* life -- the definition itself targets $s1 directly, with NO copy. The target,
* however, computes into $a0 first (its natural scratch there) and only copies into
* $s1 in the FIRST clamp branch's delay slot -- i.e. genuinely TWO pseudos joined by
* a real `addu $s1,$a0,$zero` that must survive both cse's copy-propagation AND local
* scheduling picking it (not the clamp's own field store) to fill that delay slot.
* FIX: `register s32 tmp __asm__("$4"); register s32 t __asm__("$17");` -- pinning
* BOTH ends to their target hard registers stops cse from unifying them (neither
* register can be "renamed away") and gives the scheduler exactly the copy the
* target has, in the position the target has it. An UNPINNED two-variable split
* (`t = tmp;`) is not enough by itself: cse/copy-prop still eliminates it. Reusing
* `tmp` a second time for the clamp subtraction ALSO defeats the copy-elimination
* (a real redefinition blocks the fold) but then clobbers $a0's `t` value TOO EARLY
* (before the branch), forcing the copy to schedule immediately instead of into the
* delay slot (76/78 ins, LENGTH-DRIFT). The double-pin is the only variant tried
* that reproduces both the register split AND its exact scheduling position.
* @stuck: none -- MATCH (match_one), first iteration after the double-pin.
*
* INTEGRATION NOTE (§161c-style): the SVECTOR_8017C290 typedef below is here ONLY so
* this file compiles STANDALONE for match_one. The real host TU already provides it
* at file scope ahead of func_8017C290 (~L3420, per that function's own "provided by
* the TU (§100)" comments) -- when banking, DROP this typedef and rely on the TU's
* existing one; do not leave a duplicate at the integration point.
*/
#include "common.h"
extern s32 func_80146E98(s32 a0);
extern void func_80147324(s32 arg0);
extern void func_80146C3C(void);
extern void func_8017D318(int a0, SVECTOR_8017C290 *a1, SVECTOR_8017C290 *a2, s32 a3);
extern u16 D_8018EFFC[][2];
void func_8017D1E0(void *a0)
{
s16 n;
register s32 tmp __asm__("$4");
register s32 t __asm__("$17");
s16 v;
SVECTOR_8017C290 vec1;
SVECTOR_8017C290 vec2;
n = *(s16 *)((s32)a0 + 0x28);
if (n != 0) {
n = n - 1;
*(s16 *)((s32)a0 + 0x28) = n;
if (n == 0) {
func_80147324(D_8018EFFC[*(s32 *)((s32)a0 + 0x2C)][0]);
}
}
tmp = *(s32 *)((s32)a0 + 0x30) + 0x6000;
*(s32 *)((s32)a0 + 0x14) += tmp;
t = tmp;
v = *(u16 *)((s32)a0 + 0x10) - *(u16 *)((s32)a0 + 0x16);
*(s16 *)((s32)a0 + 0x10) = v;
if (v < 0) {
*(s16 *)((s32)a0 + 0x10) = 0;
}
if (func_80146E98((s32)a0)) {
*(s32 *)((s32)a0 + 0x18) += t;
v = *(u16 *)((s32)a0 + 0x12) - *(u16 *)((s32)a0 + 0x1A);
*(s16 *)((s32)a0 + 0x12) = v;
if (v < 0) {
*(s16 *)((s32)a0 + 0x12) = 0;
}
}
vec1.vx = 0;
vec1.vy = *(u16 *)((s32)a0 + 0x10);
vec1.vz = 1;
vec2.vx = 0;
vec2.vy = *(u16 *)((s32)a0 + 0x12);
vec2.vz = 1;
func_8017D318((int)a0, &vec1, &vec2, *(s16 *)((s32)a0 + 0x24));
if (*(s32 *)((s32)a0 + 0x10) == 0) {
((void (*)(s32))func_80146C3C)((s32)a0);
}
}
/* func_8017D318 -- ov_SC03_014, TU ov_SC03_014_jr_8017AE2C.c
*
+1 -1
View File
@@ -2661,7 +2661,7 @@ extern void func_8017BFC8(void *a0);
extern void func_8017C07C(void);
extern void (*D_8018F024[])(void);
extern void func_8017C0C8(void *a0);
extern void func_8017C154(void);
extern void func_8017C154();
extern void func_8017C12C(void);
extern void func_8017C14C(void);
extern void (*D_8018F064[])(void);
+1 -1
View File
@@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0);
extern void func_8017C07C(void);
extern void (*D_8018F024[])(void);
extern void func_8017C0C8(void *a0);
extern void func_8017C154(void);
extern void func_8017C154();
extern void func_8017C12C(void);
extern void func_8017C14C(void);
extern void (*D_8018F064[])(void);
+1 -1
View File
@@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0);
extern void func_8017C07C(void);
extern void (*D_8018F024[])(void);
extern void func_8017C0C8(void *a0);
extern void func_8017C154(void);
extern void func_8017C154();
extern void func_8017C12C(void);
extern void func_8017C14C(void);
extern void (*D_8018F064[])(void);
+1 -1
View File
@@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0);
extern void func_8017C07C(void);
extern void (*D_8018F024[])(void);
extern void func_8017C0C8(void *a0);
extern void func_8017C154(void);
extern void func_8017C154();
extern void func_8017C12C(void);
extern void func_8017C14C(void);
extern void (*D_8018F064[])(void);
+1 -1
View File
@@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0);
extern void func_8017C07C(void);
extern void (*D_8018F024[])(void);
extern void func_8017C0C8(void *a0);
extern void func_8017C154(void);
extern void func_8017C154();
extern void func_8017C12C(void);
extern void func_8017C14C(void);
extern void (*D_8018F064[])(void);
+46 -1
View File
@@ -4607,7 +4607,52 @@ INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8018164
INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_801816C8);
INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8018171C);
#include "common.h"
extern s32 func_8004787C(s32 a0);
extern s32 func_8014CB0C(void);
extern s32 rand(void);
extern void func_80181F88(s32 a0, s32 a1);
extern void func_8012CBF4(s32 a0);
extern void func_80182288(s16 *a0, s32 a1);
extern void func_80181ED4(s32 a0);
void func_8018171C(s32 a0) {
s16 sp10[3];
s32 pad[2];
if ((*(u16 *)(a0 + 0x70) & 1) == 0) {
*(s16 *)(a0 + 0x52) = (u32)func_8004787C(*(s32 *)(a0 + 0x1C) << 5) >> 8;
if (*(s32 *)(a0 + 0x1C) == (*(s32 *)(a0 + 0x1C) / 24) * 24) {
sp10[0] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0x8);
sp10[1] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0xA) + 0x40;
sp10[2] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0xC);
func_80182288(sp10, 0x60);
}
} else {
if (*(u8 *)(a0 + 0x1C) == 0) {
s32 r = rand();
*(s32 *)(a0 + 0xE8) = (r % 64) + 0x40;
}
if (func_8014CB0C() == 0) {
func_80181F88(a0, 0xFFFD8000);
func_8012CBF4(a0);
*(u16 *)(a0 + 0xA) = *(u16 *)(a0 + 0x8A);
}
if (*(s32 *)(a0 + 0x1C) == (*(s32 *)(a0 + 0x1C) / 24) * 24) {
sp10[0] = *(u16 *)(a0 + 0x6);
sp10[1] = *(u16 *)(a0 + 0xA);
sp10[2] = *(u16 *)(a0 + 0xE);
sp10[1] = sp10[1] + 0x38;
func_80182288(sp10, 0x80);
}
}
func_80181ED4(a0);
*(s16 *)(*(s32 *)(a0 + 0x20) + 0x1A) =
0x2000 - (func_8004787C((*(s32 *)(a0 + 0x1C) << 5) & 0x7E0) >> 1);
*(s32 *)(a0 + 0x1C) = *(s32 *)(a0 + 0x1C) + 1;
}
#include "common.h"
+127 -1
View File
@@ -6449,7 +6449,133 @@ extern s32 rand(void);
INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017EB04);
INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017EB70);
/* func_8017EB70 (ov_SC03_107 / jr_801789AC) — 127 ins, match_one MATCH.
*
* "Chase/push-away" AI tick: read the actor's state word, bail on states 2 / 0x1A,
* clamp two fields, then walk the 0x60-entry entity table at D_801202A0 (stride
* 0x10C) looking for a nearby live neighbour and try to step this actor to a point
* 0x61 units away from it (func_8012CEB0 is the collision/move probe).
*
* Provenance (cookbook §160g sibling search): the INNER half is the already-banked
* func_8017E404 in src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c:4538 — same
* ratan2->func_8012B0B4->`d = *(s32*)&buf`->out.vx/out.vz packed-offset idiom, same
* SVEC in/out/buf stack order. The OUTER counted walk is the in-TU banked
* func_801822E4 (same file, :7772): `p = D_801202A0; for (i=0;i<0x60;i++)`.
*
* Three non-obvious levers, in the order the gate found them:
*
* 1. `lose:` INSIDE the 0x1A arm (cookbook §162g). The target's `beqz $v0,
* .L8017EBDC` at 0x8017ECFC is a BACKWARD branch into a block emitted between the
* 0x1A arm and the 0x2000 test. Per §162g cross-jumping only ever emits FORWARD
* merges, so this edge can only be a source-level `goto`. Putting the label
* after the arm's `return 0;` (C permits a goto into a block) reproduces the
* block order with zero extra jumps — no `if (0) {}` wrapper, no jump threading
* needed.
*
* 2. `bp` exists only to create a MOVABLE (cookbook §162e2). `&buf` passed straight
* to func_8012B0B4 is expanded into the arg register in place, so scan_loop has
* nothing to hoist: the draft was 124 ins with only $s0-$s5 and no
* `addiu $s6,$sp,0x20` preheader hoist. Naming it forces a pseudo, which becomes
* the second movable (after `arg0 + 4`), lands in $s6, and the preheader order
* falls out as body order: $s0, $s4, $s5, $s6, then the +0xE giv $s2. (&in/&out
* stay unnamed — the target keeps THOSE inline as `addiu $a0,$sp,0x10` /
* `addiu $a1,$sp,0x18`.) -3 ins -> 0.
*
* 3. `i++, p += 0x10C` in the FOR-INCREMENT, not `p += 0x10C;` as the last body
* statement. The +0xE giv's increment is emitted adjacent to its biv ($s0), so
* body-tail `p += ...` gives [$s2++, $s4++] and the comma form gives the target's
* [$s4++, $s2++]. Last 2 mismatched instructions.
*
* INTEGRATION (§161c): every extern below except func_8017EEA8 is ALREADY declared
* at file scope in src/ov_SC03_107/ov_SC03_107_jr_801789AC.c, identically —
* D_801202A0 :338, func_8012ADE4 :349, func_8012B0B4 :361, func_8012B6D4 :382,
* func_8012BC60 :397, func_8012CBA4 :452, func_8012CEB0 :458, func_80131E00 :562.
* The whole extern block may be dropped on banking. func_8012CBA4 is declared
* `void` there and func_8012BC60/func_80131E00 take struct pointers, so all three
* are reached through call-site function-pointer casts (codegen-neutral, §17a-1) —
* verified MATCH both with those casts against loose `()` decls and against the TU's
* exact struct-typed prototypes. func_8017EEA8 has no decl in the TU (it is
* INCLUDE_ASM at :6456), so its extern must be kept. SVEC_EB70 is a fresh tag —
* no collision in the TU.
*/
#include "common.h"
typedef struct { s16 vx, vy, vz, pad; } SVEC_EB70;
struct Vec;
struct S80131E00;
extern u8 D_801202A0[];
extern void func_8012CBA4(s32 a0); /* TU decl is void -> cast at call site */
extern void func_80131E00(struct S80131E00 *a0, s32 a1);
extern void func_8017EEA8(void *a0);
extern void func_8012ADE4(u8 *a0);
extern s32 func_8012BC60(struct Vec *a0, struct Vec *a1);
extern s32 func_8012B6D4(s16 *a0, s16 *a1);
extern void func_8012B0B4(unsigned int *param_1, int param_2, int param_3);
extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
s32 func_8017EB70(s32 arg0) {
SVEC_EB70 in;
SVEC_EB70 out;
SVEC_EB70 buf;
s32 v;
s32 d;
s32 i;
u8 *p;
u16 px, pz;
unsigned int *bp;
v = ((s32 (*)(s32))func_8012CBA4)(arg0);
if ((v & 0xFF) == 2) {
((void (*)(s32, s32))func_80131E00)(arg0, 0x12);
return 0;
}
if ((v & 0xFF) == 0x1A) {
func_8017EEA8((void *)arg0);
return 0;
lose:
func_8012ADE4((u8 *)arg0);
return 1;
}
if ((v & 0x2000) == 0) {
func_8012ADE4((u8 *)arg0);
}
*(s32 *)(arg0 + 0xDC) &= ~0x40;
if (*(s32 *)(arg0 + 0x14) > 0xFFFFF) {
*(s32 *)(arg0 + 0x14) = 0x100000;
}
p = D_801202A0;
for (i = 0; i < 0x60; i++, p += 0x10C) {
if (*(u16 *)p != 0 && *(s32 *)(p + 0x58) != 0 && arg0 != (s32)p) {
if (((s32 (*)(s32, s32))func_8012BC60)(arg0 + 4, (s32)(p + 4)) < 0x2400) {
bp = (unsigned int *)&buf;
func_8012B0B4(bp,
func_8012B6D4((s16 *)(arg0 + 4), (s16 *)(p + 4)), 0x61);
d = *(s32 *)&buf;
px = *(u16 *)(p + 6);
out.vx = px;
out.vy = *(u16 *)(p + 0xA);
pz = *(u16 *)(p + 0xE);
out.vz = pz;
out.vx = px + d;
out.vz = pz + (d >> 16);
in.vx = *(u16 *)(arg0 + 0x3A);
in.vy = *(u16 *)(arg0 + 0x3E);
in.vz = *(u16 *)(arg0 + 0x42);
if ((func_8012CEB0((s32)&in, (s32)&out, 0) & 0x2000) == 0) {
goto lose;
}
*(s16 *)(arg0 + 6) = out.vx;
*(s16 *)(arg0 + 0xA) = out.vy;
*(s16 *)(arg0 + 0xE) = out.vz;
break;
}
}
}
return 1;
}
INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017ED6C);
+119 -2
View File
@@ -3391,7 +3391,67 @@ void func_80186B78(s32 a0)
}
INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187180);
#include "common.h"
extern s32 func_8012B8E4(s32 a0, s32 a1);
extern void func_8012B1B4(s32 a0, s32 a1);
extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
extern s32 func_8012BCCC(s32 a0);
extern s32 func_8012BDBC(s32 a0, s32 a1);
extern void func_8012CC40(s32 arg0, s32 arg1); /* fleet-canonical: void; $v0 used -> cast at call site */
void func_80187180(s32 a0)
{
extern u8 D_801C6FA8[];
extern s32 D_801C6FC4;
s16 pos1[4];
s16 pos2[4];
s32 s1;
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) += func_8012B8E4(a0, 0x10);
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) &= 0xFFF;
func_8012B1B4(a0, (s32)D_801C6FA8);
{
s16 *p1 = pos1;
s16 *p2 = pos2;
s32 x, y, z;
x = *(u16 *)(a0 + 0x6);
p2[0] = x;
p1[0] = x;
y = *(u16 *)(a0 + 0xA);
p2[1] = y;
p1[1] = y;
z = *(u16 *)(a0 + 0xE);
p2[1] = y + 0x40;
p2[2] = z;
p1[2] = z;
s1 = func_8012CEB0((s32)p1, (s32)p2, 1);
}
if (s1 & 0x6000) {
if (!(s1 & 0x1000)) {
s1 = func_8012BCCC(a0);
if (s1 < 0x4001) {
if (func_8012BDBC(a0, 0x200) == 1) {
*(s16 *)(a0 + 0x2) = 4;
*(s16 *)(a0 + 0xFC) = 0;
*(s16 *)(a0 + 0x100) = *(u16 *)(a0 + 0xA);
}
}
}
}
if (s1 > 0x40000) {
*(s16 *)(a0 + 0x2) = 1;
}
if ((((s32 (*)(s32, s32))func_8012CC40)(a0, (s32)&D_801C6FC4) & 0x1000) != 0) {
*(s16 *)(a0 + 0x2) = 0x12;
}
}
#include "common.h"
@@ -3699,7 +3759,64 @@ INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187A8
INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187AEC);
INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187B80);
extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2);
extern void func_8012B23C(s32 a0);
extern void func_8012B1B4(s32 a0, s32 a1);
void func_80187B80(s32 a0)
{
extern u8 D_801C6FA8[];
u16 out[4];
u16 pos[4];
u16 t0, t1, t2;
*(u16 *)(a0 + 0x5C) = 0xA810;
*(u16 *)(a0 + 0x2) = *(u16 *)(a0 + 0x34);
t0 = *(u16 *)(a0 + 0x6);
pos[0] = t0;
out[0] = t0;
t1 = *(u16 *)(a0 + 0xA);
pos[1] = t1;
out[1] = t1 - 0x18;
t2 = *(u16 *)(a0 + 0xE);
pos[2] = t2;
out[2] = t2;
func_8012CEB0((s32)out, (s32)pos, 1);
*(u16 *)(a0 + 0xA) = pos[1] - 0x10;
if (*(s16 *)(a0 + 0x70) == 0xF) {
s32 c;
c = *(s32 *)(a0 + 0x20);
*(u16 *)(c + 0x14) = 0;
*(u16 *)(a0 + 0x2) = 1;
*(u16 *)(a0 + 0x34) = 1;
*(u16 *)(a0 + 0x70) = 0;
*(u16 *)(a0 + 0x88) = *(u16 *)(a0 + 0x6);
*(u16 *)(a0 + 0x8A) = *(u16 *)(a0 + 0xA);
*(u16 *)(a0 + 0x8C) = *(u16 *)(a0 + 0xE);
func_8012B23C(a0);
func_8012B1B4(a0, (s32)D_801C6FA8);
{
s32 n = *(s32 *)(a0 + 0x6C);
while (n != 0) {
*(u16 *)(n + 0x2) = 2;
*(u16 *)(n + 0x70) = *(u16 *)(n + 0x70) - 0x10;
*(u16 *)(*(s32 *)(n + 0x20) + 0x14) = 0;
n = *(s32 *)(n + 0x6C);
}
}
*(u16 *)(a0 + 0xFC) = 0;
} else {
func_8012B23C(a0);
func_8012B1B4(a0, (s32)D_801C6FA8);
}
}
extern void func_8012E688(s32 *a0, s32 a1, s32 a2);
void func_80187CA8(void *a0) {
+58 -1
View File
@@ -4356,7 +4356,64 @@ extern void func_8017ED80(void);
INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_8017FF74);
INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_80180000);
extern s32 func_8012C354(s32 a0, s32 a1);
extern void func_80143970();
extern void func_8012A828(s32 a0, void *a1);
extern void func_8012B200(u8 *a0);
extern void func_8012C1B8(void);
extern void func_8001C214(s32 a0, s32 a1);
extern void func_80016714(void *a0, s32 a1);
extern void func_8012CAE4(void *a0);
void func_80180000(s32 a0) {
extern u8 D_8019C808[];
extern u8 D_8019E548[];
extern u8 D_8019C83C[];
extern u8 D_8019E258[];
extern u8 D_8019E530[];
extern u8 D_80185B40[];
s32 s0;
u16 t;
if (func_8012C354(a0, D_8019C808) == 0) {
return;
}
*(u8 *)(a0 + 0xC0) = 1;
*(s32 *)(a0 + 0xB4) = -0x1001;
((s32 (*)(s32))func_80143970)(a0);
func_8012A828(a0, D_8019E548);
*(u16 *)(a0 + 0x2) += 1;
func_8012B200((u8 *)a0);
*(s32 *)(a0 + 0xBC) = (s32)D_8019C83C;
s0 = ((s32 (*)(void))func_8012C1B8)();
if (s0 == 0) {
goto fail;
}
*(s32 *)(a0 + 0xCC) = s0;
func_8001C214(s0, (s32)D_8019E258);
t = *(u16 *)(s0 + 0x2C) | 0x10;
*(s32 *)(s0 + 0x20) = *(s32 *)D_80185B40;
*(u16 *)(s0 + 0x2C) = t;
s0 = ((s32 (*)(void))func_8012C1B8)();
if (s0 == 0) {
func_80016714((void *)*(s32 *)(a0 + 0xCC), 0x84);
fail:
func_8012CAE4((void *)a0);
return;
}
*(s32 *)(a0 + 0xD0) = s0;
func_8001C214(s0, (s32)D_8019E530);
t = *(u16 *)(s0 + 0x2C) | 0x10;
*(s32 *)(s0 + 0x20) = *(s32 *)D_80185B40;
*(u16 *)(s0 + 0x2C) = t;
*(u16 *)(a0 + 0x100) = 0x3C;
*(s32 *)(a0 + 0xDC) = 0xFFFC0000;
}
INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_80180128);
+347 -4
View File
@@ -7061,7 +7061,86 @@ void func_80184C74(s32 p)
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_801850F4);
#include "common.h"
/* Host TU: src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c
* Insertion point replaces the INCLUDE_ASM at line 6996, in scope after the
* decl block that begins at line 6786 (#include "common.h"). That block
* ALREADY declares (in scope, do not redeclare):
* extern s32 func_8012BEE8(); (line 6789)
* extern void func_8012A828(s32 a0, void *a1); (line 6790)
* extern u8 D_801CC868[]; (line 6803)
* and elsewhere earlier in the SAME TU (still in scope, file-scope extern):
* extern void func_80013350(s32 a0, void *a1); (line 6647)
* -- loose prototype (real callee takes/returns s32,s32->s32); per
* cookbook §161c do NOT add a conflicting extern here, cast at the
* call site instead (matches the TU's own sibling func_8018457C).
* New decls needed for this function (not yet declared in this TU's scope
* at the insertion point):
* func_8012B6D4, func_8012B608, func_8012B178, func_8018765C,
* func_8012C218, func_8001C924, D_801CD0E8[], D_801BC090[]
* (func_8012B6D4/B608/B178/8765C signatures copied verbatim from this TU's
* other declarations of the same symbols, e.g. lines 6643-6646/7043-7045;
* func_8012C218/func_8001C924 copied from lines 6639-6640.)
*/
extern s32 func_8012BEE8();
extern void func_8012A828(s32 a0, void *a1);
extern void func_80013350(s32 a0, void *a1); /* loose proto, real TU decl (line 6647); cast at call site per §161c */
extern s32 func_8012B6D4(s16 *a0, s16 *a1);
extern s32 func_8012B608(s32 a0, s32 a1, s32 a2);
extern void func_8012B178(s32 a0, s32 a1);
extern s32 func_8018765C(s32 a0);
extern void func_8012C218(void *a0);
extern void func_8001C924(s32 a0, void *a1);
extern u8 D_801CD0E8[];
extern u8 D_801CC868[];
extern u8 D_801BC090[];
void func_801850F4(s32 p)
{
s32 s1;
s32 r;
if (*(u16 *)(p + 0x34) == 0) {
s1 = *(s32 *)(p + 0xCC);
if (s1 == 0 || *(s16 *)(s1 + 0x36) != *(s16 *)(p + 0xEC) ||
func_8012BEE8(p) != 0) {
*(u16 *)(p + 2) = 0x23;
*(u32 *)(p + 0xE0) |= 0x800;
return;
}
r = func_8012B6D4((s16 *)(p + 4), (s16 *)(s1 + 4));
*(s32 *)(p + 0xE8) = r;
r = func_8012B608(*(s16 *)(*(s32 *)(p + 0x20) + 0x12), *(s32 *)(p + 0xE8), 8);
*(u16 *)(*(s32 *)(p + 0x20) + 0x12) =
*(u16 *)(*(s32 *)(p + 0x20) + 0x12) + r;
func_8012B178(p, 0xFFF8D000);
func_8018765C(p);
r = ((s32 (*)(s32, s32))func_80013350)(p + 4, s1 + 4);
if (r < 0x900) {
*(u16 *)(p + 0x34) = *(u16 *)(p + 0x34) + 1;
func_8012A828(p, D_801CD0E8);
}
} else {
if (*(s16 *)(p + 0x98) != 0) {
return;
}
func_8012C218((void *)*(s32 *)(p + 0xCC));
*(s32 *)(p + 0xCC) = 0;
func_8001C924(*(s32 *)(p + 0x20), D_801BC090);
func_8012A828(p, D_801CC868);
*(s32 *)(p + 0x48) = 0x4650;
*(s16 *)(p + 2) = 0x12;
*(u32 *)(p + 0xE0) &= ~4;
}
}
#include "common.h"
@@ -7250,7 +7329,87 @@ void func_801854F8(s32 p) {
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_801857CC);
#include "common.h"
/* §160g sibling search: callee set {func_8012BEE8, func_8012B6D4, func_8012B608,
* func_8012B178, func_8018765C, func_80013350, func_8012A828, func_8012C218,
* func_8001C924} matches the ALREADY-MATCHED func_8018457C in this exact TU
* (src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c, lines 6654-6733) almost verbatim --
* that function's case 0 (the s1=*(p+0xCC) null/field-0x36-vs-0xEC/func_8012BEE8
* mismatch guard, then func_8012B6D4 + the func_8012B608/func_8012B178/
* func_8018765C/func_80013350 tail with the same D_801CD0E8 transition) is a
* structural template for our "state==0" branch. The "state!=0" branch's tail
* (set +2=0x1D, +0x34=0, +0x1C=0xF, call func_8012A828) is verbatim the body of
* the tiny already-MATCHED func_801854C0 a few lines above ours in the same TU
* (it uses a function-pointer cast only because ITS param is `short *`; ours is
* already `s32 param_1` so a plain call suffices, mirroring func_801854F8's own
* plain `func_8012A828(p, D_801CC358);` two lines before our INCLUDE_ASM slot).
* The `*(u32*)(p+0xE0) &= 0xFFFFFFFB;` mask is byte-identical to func_8018457C's
* case 1 mask. All extern decls below are copied verbatim from these matched
* siblings' own decl blocks (same TU, same file-scope conventions).
*/
extern s32 func_8012BEE8();
extern s32 func_8012B6D4(s16 *a0, s16 *a1);
extern s32 func_8012B608(s32 a0, s32 a1, s32 a2);
extern void func_8012B178(s32 a0, s32 a1);
extern s32 func_8018765C(s32 a0);
extern void func_80013350(s32 a0, void *a1);
extern void func_8012A828(s32 a0, void *a1);
extern void func_8012C218(void *a0);
extern void func_8001C924(s32 a0, void *a1);
extern u8 D_801CD0E8[];
extern u8 D_801BBC78;
extern u8 D_801CC358[];
void func_801857CC(s32 param_1)
{
s32 s1;
s32 uVar4;
s32 sVar1;
s32 r;
if (*(u16 *)(param_1 + 0x34) == 0) {
s1 = *(s32 *)(param_1 + 0xCC);
if (s1 == 0 || *(s16 *)(s1 + 0x36) != *(s16 *)(param_1 + 0xEC) ||
func_8012BEE8(param_1) != 0) {
*(s16 *)(param_1 + 2) = 0x23;
*(u32 *)(param_1 + 0xE0) |= 0x800;
return;
}
uVar4 = func_8012B6D4((s16 *)(param_1 + 4), (s16 *)(s1 + 4));
*(s32 *)(param_1 + 0xE8) = uVar4;
sVar1 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), uVar4, 8);
*(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) =
*(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + sVar1;
func_8012B178(param_1, 0xFFF8D000);
func_8018765C(param_1);
r = ((s32 (*)(s32, s32))func_80013350)(param_1 + 4, s1 + 4);
if (r < 0x900) {
*(u16 *)(param_1 + 0x34) = *(u16 *)(param_1 + 0x34) + 1;
func_8012A828(param_1, D_801CD0E8);
}
return;
}
if (*(s16 *)(param_1 + 0x98) != 0) {
return;
}
func_8012C218((void *)*(s32 *)(param_1 + 0xCC));
*(s32 *)(param_1 + 0xCC) = 0;
func_8001C924(*(s32 *)(param_1 + 0x20), &D_801BBC78);
*(s16 *)(param_1 + 2) = 0x1D;
*(u16 *)(param_1 + 0x34) = 0;
*(s32 *)(param_1 + 0x1C) = 0xF;
func_8012A828(param_1, D_801CC358);
*(u32 *)(param_1 + 0xE0) &= 0xFFFFFFFB;
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185944);
@@ -7356,7 +7515,75 @@ void func_8018598C(s32 param_1) {
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185C2C);
#include "common.h"
/* Sibling-search hit (cookbook §160g): src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:6654
* func_8018457C (already banked) is the SAME structural family — its case 0 (the
* s0==0||mismatch||func_8012BEE8() guard + call_b6d4/LAB_80184738 tail) and case 3
* (func_8012C218/func_8001C924/func_8012A828 teardown chain) are literally this
* function's two branches with different field offsets/globals. Types/signatures below
* mirror that TU's existing extern decls exactly (host TU already declares all of
* these at file scope before this insertion point, e.g. lines 6639-6652, 7203-7213).
*/
extern s32 func_8012BEE8(s32 a0);
extern s32 func_8012B6D4(s16 *a0, s16 *a1);
extern s32 func_8012B608(s32 a0, s32 a1, s32 a2);
extern void func_8012B178(s32 a0, s32 a1);
extern s32 func_8018765C(s32 a0);
extern void func_80013350(s32 a0, void *a1);
extern void func_8012A828(s32 a0, void *a1);
extern void func_8012C218(void *a0);
extern void func_8001C924(s32 a0, void *a1);
extern u8 D_801CD0E8[];
extern u8 D_801BC494;
extern u8 D_801CC6E8[];
void func_80185C2C(s32 p)
{
s32 s0;
s32 r;
if (*(u16 *)(p + 0x34) == 0) {
s0 = *(s32 *)(p + 0xCC);
if (s0 == 0 || *(s16 *)(s0 + 0x36) != *(s16 *)(p + 0xEC) ||
func_8012BEE8(p) != 0) {
*(u16 *)(p + 2) = 0x23;
*(u32 *)(p + 0xE0) |= 0x800;
} else {
r = func_8012B6D4((s16 *)(p + 4), (s16 *)(s0 + 4));
*(s32 *)(p + 0xE8) = r;
r = func_8012B608(*(s16 *)(*(s32 *)(p + 0x20) + 0x12), *(s32 *)(p + 0xE8), 8);
*(u16 *)(*(s32 *)(p + 0x20) + 0x12) =
*(u16 *)(*(s32 *)(p + 0x20) + 0x12) + r;
func_8012B178(p, 0xFFF8D000);
func_8018765C(p);
r = ((s32 (*)(s32, s32))func_80013350)(p + 4, s0 + 4);
if (r < 0x900) {
*(u16 *)(p + 0x34) = *(u16 *)(p + 0x34) + 1;
func_8012A828(p, D_801CD0E8);
}
}
} else {
if (*(s16 *)(p + 0x98) == 0) {
func_8012C218((void *)*(s32 *)(p + 0xCC));
*(s32 *)(p + 0xCC) = 0;
func_8001C924(*(s32 *)(p + 0x20), &D_801BC494);
*(u16 *)(p + 2) = 0x20;
func_8012A828(p, D_801CC6E8);
*(s32 *)(p + 0x48) = 0x4650;
*(s32 *)(p + 0x1C) = 0;
*(s32 *)(p + 0xE4) = 0;
*(u32 *)(p + 0xE0) &= 0xFFFFFFFB;
}
}
}
extern void func_80187038(void);
void func_80185DA8(s32 arg0) {
@@ -7366,7 +7593,123 @@ extern void func_80187038(void);
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185DD8);
#include "common.h"
/* Sibling-search (§160g) findings, kept for the integration note:
* - func_8018598C (same TU, ov_SC06_018_jr_8017C24C.c:7215, MATCHED/banked already) shares
* func_8012BEE8/func_8012B608/func_8012B178/func_8018765C/func_801877E4 with identical
* argument shapes -- confirms every extern signature below except func_8012B8A4/func_8012EFB8.
* - func_8018457C (same TU, :6654) uses the SAME func_8012B608(*(s16*)(*(s32*)(p+0x20)+0x12),
* *(s32*)(p+0xE8), 8) / field += pattern and the SAME func_8012B178(p, 0xFFF8D000) magic
* literal -- confirms the b608/b178 idiom byte-for-byte.
* - func_8012B8A4 canonical decl (many matched TUs): extern s32 func_8012B8A4(s16 *a0);
* - func_8012EFB8's byte-true body (src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c:1106) is
* `s32 func_8012EFB8(void *param_1, void *param_2)` -- TWO pointers, s32 return -- but the
* fleet-canon extern in THIS TU (line 335: `extern void func_8012EFB8(s32 a0);`, file scope,
* already in effect before this function) conflicts on both arity and return axis. Per §161c,
* do NOT add a second extern; cast the existing symbol at the call site instead.
* - Ghidra seed at .run/ghidra_c/func_80185DD8.c confirms the callee set and control flow
* (verified address-matched: FUN_80185dd8, calls FUN_8012be54/bee8/b8a4/b608/b178/8765c/877e4/
* efb8/c098) -- used only to cross-check, not copied verbatim (Ghidra's decompile is
* -O0-shaped and not reg-alloc-accurate).
*
* INTEGRATION SURFACE (for the banking step): every extern below is checked against this TU's
* (ov_SC06_018_jr_8017C24C.c) own file-scope decls already in effect before line 7301:
* func_8012BE54 -> void(s32) EXACT match (host decl at :4212/:5193; cast to (s32(*)(s32)) at
* the one call site, mirroring the host's own existing call-site casts at :4363/:5291).
* func_8012BEE8 -> s32(s32) EXACT match (:7203).
* func_8012B608 -> s32(s32,s32,s32) EXACT match (:6644).
* func_8012B178 -> void(s32,s32) EXACT match (:6645/:7044/:7207).
* func_8018765C -> s32(s32) EXACT match (:6646/:7045/:7208).
* func_801877E4 -> void(s32) EXACT match (:7046/:7209).
* func_8012EFB8 -> declared void(s32) to match the host's loose file-scope decl (:335); the
* real (void*,void*)->s32 body is invoked through a cast at the call site (§161c), so no
* second/conflicting extern is introduced.
* func_8012C098 -> void(void*) EXACT match (:5603).
* func_8012B8A4 -> NOT declared anywhere in this TU before this point; the draft's
* `extern s32 func_8012B8A4(s16 *a0);` is the canonical signature used fleet-wide and
* introduces no conflict.
* Net: zero declaration conflicts predicted against the host TU.
*/
extern void func_8012BE54(s32 a0); /* host TU decl is void (§161c-style loose proto); cast at call site */
extern s32 func_8012BEE8(s32 a0);
extern s32 func_8012B8A4(s16 *a0);
extern s32 func_8012B608(s32 a0, s32 a1, s32 a2);
extern void func_8012B178(s32 a0, s32 a1);
extern s32 func_8018765C(s32 a0);
extern void func_801877E4(s32 a0);
extern void func_8012EFB8(s32 a0); /* loose decl, real body is (void*,void*)->s32; call via cast */
extern void func_8012C098(void *param_1);
void func_80185DD8(s32 a0) {
s32 r;
s16 vecA[4];
s16 vecB[4];
s32 x, z;
if ((*(u32 *)(a0 + 0xE0) & 0x40) == 0) {
s32 ret = ((s32 (*)(s32))func_8012BE54)(a0);
if (ret <= 0x63FFF) {
if (func_8012BEE8(a0) != 0) {
s32 t;
s32 rr;
t = func_8012B8A4((s16 *)a0);
*(u32 *)(a0 + 0xE8) = (t + 0x800) & 0xFFF;
rr = rand();
*(s32 *)(a0 + 0x1C) = rr % 0x40 + 0x40;
}
}
}
r = func_8012B608((s32) * (s16 *)(*(s32 *)(a0 + 0x20) + 0x12), *(s32 *)(a0 + 0xE8), 8);
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) = *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) + r;
*(u32 *)(a0 + 0xE0) &= 0xFFFFFFBF;
func_8012B178(a0, 0xFFF8D000);
if (func_8018765C(a0) == 0) {
func_801877E4(a0);
}
vecA[0] = *(s16 *)(a0 + 0x6);
vecA[1] = *(s16 *)(a0 + 0xA);
vecA[2] = *(s16 *)(a0 + 0xE);
((s32 (*)(void *, void *))func_8012EFB8)(vecA, vecB);
x = vecB[0];
if (x < 0) {
x = -x;
}
if (x < 0x105) {
z = vecB[1];
if (z >= 0) {
if (z < 0xC9) {
/* NEW LEVER (not yet in cookbook): a bare if/else-with-return here compiles
* to a value-converge merge (ONE shared `slti`+`bne` fed by both signs of z,
* ~91 ins) instead of the target's genuine PER-BRANCH duplicate compare
* (96 ins: `bltz`+`slti`+`beqz`+`j` in this arm, `negu`+`slti`+`bnez` in the
* else arm). A zero-emission `__asm__ __volatile__("":::"memory")` right
* before this `return` is a scheduling/combine barrier that blocks whatever
* RTL-level pass performs that merge, without adding a single byte itself --
* the compiled result is byte-exact target. Byte-proven via 9 probe variants
* (assignment-abs, ternary-condition, if/else, 2-independent-ifs, goto-labeled
* return) that ALL either fully merged or left a redundant extra sign-retest;
* only this barrier reproduces the target exactly. See match_one MATCH 96/96.
*/
__asm__ __volatile__("" ::: "memory");
return;
}
} else {
if (-z < 0xC9) {
return;
}
}
}
func_8012C098((void *)a0);
}
#include "common.h"
+155 -2
View File
@@ -3201,7 +3201,85 @@ void func_80188088(void *a0) {
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_801880C4);
#include "common.h"
/* Sibling-search (cookbook §160g): every declaration below is TU-canonical, lifted verbatim
* from src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c (the destination TU):
* func_8012C354 -- decl at TU:2846 "extern s32 func_8012C354(s32 a0, void *a1);"
* func_8012CAE4 -- decl at TU:2849 "extern void func_8012CAE4(s32 a0);"
* func_80143994 -- decl at TU:2847 "extern s32 func_80143994(s32 a0, s32 a1);"
* func_80188B00 -- ALREADY DEFINED in this TU at :3492 "void func_80188B00(s32 p)" (banked)
* func_8012C1B8 -- TU-canonical `void (void)` at :4123/:3929, called via the established
* cast-through-function-pointer idiom (§161c) seen in this TU's own
* func_80189A34 (:4138) and func_801894F0 (:3948) -- byte-identical spawn
* idiom, same handle-alloc-then-null-check shape as our case 2.
* func_8001CA1C -- not yet declared in THIS TU; canonical form taken from the sibling TU
* ov_SC06_018_jr_80140608.c:1704 "extern void func_8001CA1C(s32 a0, s32 a1);"
* func_80188234 -- INCLUDE_ASM in this TU at :3206 (still unmatched); called here with the
* object pointer and its own return discarded, so declared void(s32).
* D_801B545C / D_801B5490 / D_801B5430 are new (undeclared anywhere in src/); declared as
* plain byte arrays per this TU's own convention for opaque data blobs (e.g. D_801AD470[]
* at TU:2791) -- only their address is used (func_8012C354's a1 is void*, func_8001CA1C's a1
* is a raw s32 cast of the address), so element type is codegen-irrelevant.
*/
extern s32 func_8012C354(s32 a0, void *a1);
extern void func_8012CAE4(s32 a0);
extern s32 func_80143994(s32 a0, s32 a1);
extern void func_80188234(s32 a0);
extern void func_8012C1B8(void);
extern void func_8001CA1C(s32 a0, s32 a1);
extern void func_80188B00(s32 p);
extern u8 D_801B545C[];
extern u8 D_801B5490[];
extern u8 D_801B5430[];
void func_801880C4(s32 a0) {
s32 v1;
s32 obj;
v1 = *(u16 *)(a0 + 0x70) & 0xF;
switch (v1) {
case 0:
if (func_8012C354(a0, D_801B545C) == 0) {
return;
}
*(s32 *)(*(s32 *)(a0 + 0x20) + 0x20) = a0 + 0xE8;
*(u16 *)(a0 + 0x104) = 0x78;
func_80188234(a0);
func_80143994(a0, 0x1800);
return;
case 1:
if (func_8012C354(a0, D_801B5490) == 0) {
return;
}
*(u16 *)(a0 + 0x104) = 0xA0;
if ((*(s16 *)(a0 + 0x70) & 0x8000) == 0) {
*(s16 *)(a0 + 0x2) = 3;
return;
}
*(s16 *)(a0 + 0x2) = 5;
func_80143994(a0, 0x1800);
return;
case 2:
obj = ((s32 (*)(void))func_8012C1B8)();
*(s32 *)(a0 + 0x20) = obj;
if (obj == 0) {
func_8012CAE4(a0);
return;
}
func_8001CA1C(obj, (s32)D_801B5430);
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x18) = 0x14CC;
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x1A) = 0x1199;
*(s32 *)(*(s32 *)(a0 + 0x20) + 4) |= 0x58000000;
*(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10;
func_80188B00(a0);
return;
default:
return;
}
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_80188234);
@@ -4997,7 +5075,82 @@ void func_8018D870(void *arg) {
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_8018DE60);
// func_8018DE60 -- ov_SC06_018 / ov_SC06_018_jr_80187AEC
//
// Structural sibling of func_8018E188 (SAME TU, banked MATCH, this file: func_8018E188).
// Shares VERBATIM: the 0x60 gate + 0x1D snapshot block, the 0x78/0x60 decrement block
// (AND form -- see E188's @stuck note), the 0x82&1 finisher, and the C8/C9 pokes.
// Diverges after that: instead of E188's 0x76<0 spawn-loop / CC-D0-D4 reseed, this
// function's 0x76<0 arm sets a distinct "state 2" field group (offsets 2/0x5C/0x34/
// 0xC1/0xF4 + clears bit 0x80 of *(p+0x20)->0x2C), and its else arm plays a different
// sound (func_8002D4C8(0xAD8,0) vs E188's 0xAE0) then tail-calls func_8018D654 (still
// INCLUDE_ASM in this TU -- no other TU references it, so this call site sets its own
// convention: void func_8018D654(void *)).
//
// @class: regalloc-order
// @stuck: none -- see match_one output.
extern void func_8016AA50(s32, s32);
extern s32 func_8016B428(s32);
extern void func_80019064(void *);
extern void func_8002A520(int);
extern void func_8002A790(int);
extern void func_8002D4C8(s32, s32);
extern void func_8018D654(void *);
extern u8 D_801D1210;
void func_8018DE60(void *arg) {
u8 *p = (u8 *)arg;
s32 e = *(u8 *)(p + 0x5E);
if (*(s16 *)(p + 0x60) != 0) {
if (e == 0x1D) {
*(u16 *)(p + 0x82) = 0;
*(u16 *)(p + 0x7C) = *(u16 *)(p + 0x06);
*(u16 *)(p + 0x7E) = *(u16 *)(p + 0x0A);
*(u16 *)(p + 0x80) = *(u16 *)(p + 0x0E);
}
{
s32 dec;
s32 q = *(s32 *)(p + 0x78);
if (q != 0 && *(s16 *)(p + 0x60) != 0) {
dec = ((s32)*(s16 *)(p + 0x60) * (s32)*(s16 *)(q + 0x30)) >> 12;
if (dec < 1) dec = 1;
} else {
dec = *(s16 *)(p + 0x60);
}
*(u16 *)(p + 0x76) = *(u16 *)(p + 0x76) - dec;
((void (*)(void *, s32))func_8016AA50)(p, dec);
}
if (*(u16 *)(p + 0x82) & 1) {
((void (*)(void *))func_8016B428)(p);
func_80019064(&D_801D1210);
}
}
if (e != 0x1D) {
if (*(u8 *)(p + 0xC8)) func_8002A520(p);
if (*(u8 *)(p + 0xC9)) func_8002A790(p);
}
if (*(s16 *)(p + 0x76) < 0) {
s32 q = *(s32 *)(p + 0x20);
*(s16 *)(p + 0x02) = 0xA;
*(u16 *)(p + 0x5C) = 0x800;
*(u16 *)(p + 0x34) = 0;
*(u8 *)(p + 0xC1) = 0;
*(s32 *)(p + 0xF4) = 1;
*(u16 *)(q + 0x2C) &= 0xFF7F;
} else {
func_8002D4C8(0xAD8, 0);
*(u16 *)(p + 0x5C) = 0x8800;
*(u16 *)(p + 0x60) = 0;
*(u8 *)(p + 0xC1) = 0;
*(u8 *)(p + 0xC2) = 0x10;
func_8018D654(p);
}
}
INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_8018DFF4);