feat(decomp): worker gate — +1 fns x0 propagated (fleet 95.2%)

This commit is contained in:
Drew T
2026-08-13 11:30:39 -06:00
parent a3d642a12a
commit 435e989834
+77 -1
View File
@@ -4010,7 +4010,83 @@ void func_8017D6F8(s32 a0)
INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_jr_8017A4AC", func_8017D748);
INCLUDE_ASM("asm/ov_SC06_010/nonmatchings/ov_SC06_010_jr_8017A4AC", func_8017D7CC);
#include "common.h"
/* func_8017D7CC @ ov_SC06_010 (subseg ov_SC06_010_jr_8017A4AC) — 87 ins.
*
* SEED: func_801822E0 @ ov_SC02_016 (src/ov_SC02_016/ov_SC02_016_jr_8017DC70.c), 91.9% skeleton-similar,
* already byte-matched. This is the near-identical sibling.
*
* Diff vs seed (byte-verified via objdump of the seed's matched .o):
* - Seed uses an explicit `s32 i = 0; do { iVar1 = func_801824AC(); if (iVar1 >= 0) {...} i++; } while (i < 3);`
* — a genuine do-while (no pre-loop guard), with the call's return value (iVar1) kept ONLY in $v1 (never
* saved across calls) and a SEPARATE loop counter `i` in $s3.
* - This target has NO separate counter: the loop variable IS the call's return value itself, tested both
* for the if-guard (>=0) and for loop continuation (<3). Because that variable is reassigned only INSIDE
* the loop body, the while-loop rotation ("if (cond) { preheader; do {...} while(cond); }") needs a
* pre-loop guard test — but since the variable has no source-level initializer before the loop, the guard
* reads whatever is in its (freshly register-allocated, never-yet-written) register: `slti $v0,$s2,3` /
* `beqz $v0,<post-loop>` right after the buf[1]-=0x40 store, with NO assignment to $s2 anywhere before it.
* Reproduced here as a genuinely uninitialized local tested by a `while` loop (matches gcc-2.7.2's
* loop-rotation idiom exactly — the guard is emitted even though the variable's "value" is indeterminate).
* - The `func_80146A6C(...)` calls' 7th argument is `1` here (not `0` as in the seed) — this constant is
* loop-invariant and reused at BOTH call sites, so gcc hoists it once into a callee-saved register ($s4)
* before the loop rather than re-materializing `li $a,1` at each site (the seed's constant is `0`, which
* is free via $zero, so the seed needed no such register — hence the seed has one fewer saved S-register).
* - The post-loop `if (cnt == 0) { ... }` here has NO else-branch (the seed's else called
* `func_80172630((u8*)param_1)`); the asm falls straight from the 3-call if-body into the epilogue.
* - Register roles differ naturally from the seed given the above (actor pointer ends up in $s3 here, not
* $s2 — $s2 is claimed by the loop-return-value variable instead).
*
* Callee/global renames from the seed (per this TU's own asm ground truth):
* func_801824AC -> func_8017D9A0 (still s32, no args)
* func_80182434 -> func_8017D928 (still void, s32 a0)
* func_80172630 -> (unused; no else-branch in this target)
*/
extern void func_80015978(s32 a0, s32 *a1);
extern s32 func_8017D9A0(void);
extern s32 func_80146A6C(s32 a0, void *a1, s32 a2, s32 a3, s32 a4, s32 a5, s32 a6);
extern int rand(void);
extern void func_8017D928(s32 a0);
extern void func_80159B3C(void *a0);
extern void func_80165718(s32 a0);
void func_8017D7CC(s32 param_1)
{
s16 buf[4];
s32 v2;
s32 uVar3;
s32 uVar4;
s32 uVar5;
s16 rnd;
u8 cnt;
func_80015978(param_1 + 4, (s32 *)buf);
buf[1] -= 0x40;
while (v2 < 3) {
v2 = func_8017D9A0();
if (v2 >= 0) {
func_80146A6C(0x51, (void *)param_1, buf[0], buf[1], buf[2], v2, 1);
uVar3 = rand();
uVar4 = rand();
uVar5 = rand();
rnd = (uVar3 & 3) * 0x400 + (uVar4 & 3) * 0xfa + (uVar5 & 3) * 0x44;
func_80146A6C(0x52, (void *)param_1, 0, -0x20, 0x10, rnd, 1);
}
}
cnt = *(u8 *)(param_1 + 0xde);
*(u8 *)(param_1 + 0xde) = cnt + 0xff;
if (cnt == 0) {
func_8017D928(param_1);
func_80159B3C((void *)param_1);
func_80165718(param_1);
}
}
extern void func_80147324(s32 a0);
extern void func_80147364(u16, s32);