From ff86e25729490a1d1ed904ec8dc4f666c51c562f Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Sat, 5 Sep 2026 18:25:13 -0600 Subject: [PATCH] =?UTF-8?q?feat(phase-32):=20T4b=20(6)=20=E2=80=94=20ov=5F?= =?UTF-8?q?SC03=5F105:=20func=5F801834A4=20(106=20ins)=20BANKED=20byte-ide?= =?UTF-8?q?ntical=20=E2=80=94=20a=20pinned=20WALL=20falls:=20a=20CSE-quant?= =?UTF-8?q?ity=20split=20hoists=20only=20the=20division's=20sign=20correct?= =?UTF-8?q?ion=20(sign=20=3D=20half=20>>=2031=20at=20the=20loop=20top;=20t?= =?UTF-8?q?he=20divide=20reads=20a=20hard-register=20copy=20so=20its=20mul?= =?UTF-8?q?t=20is=20not=20a=20movable;=20expand=5Fdivmod's=20sra=20is=20CS?= =?UTF-8?q?E'd=20into=20sign)=20(Fable=20agent)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - func_801834A4: draft .run/P32/t5x/fable/func_801834A4.c (fable agent, agent MATCH re-verified by coordinator rtu_match in the real TU) - one build for the same-TU batch: make build BINARY=ov_SC03_105 -j8 rc 0; sha1 d305ff6da199b52d0d44023766643a8b661ed524 == config/check.ov_SC03_105.sha (BYTE-IDENTICAL) - src/ov_SC03_105/ov_SC03_105_jr_80181C84.c: 2 INCLUDE_ASM left --- src/ov_SC03_105/ov_SC03_105_jr_80181C84.c | 88 ++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/ov_SC03_105/ov_SC03_105_jr_80181C84.c b/src/ov_SC03_105/ov_SC03_105_jr_80181C84.c index 274dc0482..40d949498 100644 --- a/src/ov_SC03_105/ov_SC03_105_jr_80181C84.c +++ b/src/ov_SC03_105/ov_SC03_105_jr_80181C84.c @@ -3680,7 +3680,93 @@ void func_801831E0(s32 arg0, s32 arg1) { } -INCLUDE_ASM("asm/ov_SC03_105/nonmatchings/ov_SC03_105_jr_80181C84", func_801834A4); +extern s32 rand(void); +extern s32 func_801850D8(); + +/* MATCH candidate (106/106 in match_one; see rtu_match below). T5x Fable, 2026-09-05. + * + * Carried over from the S71 body (byte-proven, do not touch): + * - `tmp` pinned to $2 forces the `addu $s6,$v0,$zero` base copy and makes the + * modulus read the pre-copy pseudo (`sll $v0,$v0,16`, not `$v0,$s6,16`). + * - `*(s32 *)(((rand() & 1) << 2) + (s32)D_8018E59C)` (sibling func_801831E0's + * spelling) keeps the D_8018E59C address from being hoisted. + * + * THE RESIDUAL THAT WAS CALLED A WALL (idx 82-89) and how it closes: + * The target hoists ONLY the /3 sign-correction `sra $s5,$s4,31` and keeps the + * const+mult+mfhi+subu inline. One `x / 3` can never do that: expand_divmod + * (expmed.c:3034-3057) emits K(const) B(smulsi3_highpart) C(sra 31) D(minus) + * ADJACENTLY from the SAME op0 rtx, so loop.c's invariant_p gives B and C the + * same verdict; if B is a movable, force_movables (loop.c:1193-1228) links K to it + * (K.lifetime += B.lifetime, K.savings DOUBLES) and K (29*6=174 >= 37) hoists. + * A hard-reg dividend kills all four (scan_loop:596 forces n_times_set[hard]=1). + * + * Lever = CSE, not loop.c. cse.c's canon_reg NEVER rewrites a hard register, but + * its hash/exp_equiv_p compare QUANTITIES. So: + * sign = half >> 31; at the TOP of the body: a movable by criterion (1) + * (maybe_never==0 there, scan_loop:696-706); life 71 -> hoisted. + * hh = half; hard $2 <- pseudo: cse puts $2 in half's quantity. + * pos[0] -= hh / 3; B reads $2 (call-used hard reg -> invariant_p==0 -> not a + * movable, so K stays unlinked: life 1 * sav 1 * 29 < 37 = + * "not desirable" -> lui/ori inline); C `(ashiftrt $2 31)` + * hashes into sign's `(ashiftrt half 31)` -> replaced by + * (reg sign); D becomes `B - sign`. The `hh = half` copy is + * then folded into the mult by combine (can_combine_p allows a + * hard i2dest with REG_DEAD in i3) -> no extra insn. + * Why $2 and not a callee-saved pin: the pinned reg enters regs_ever_live (flow runs + * before combine deletes the copy) -> global.c pass 0 hands it to the first callee-saved + * allocno (j took $s4, closeness 7). $2 is ever-live anyway and dead in that window. + * Why `= 0` at the declaration: an unread `sign` store is deleted by jump.c before cse + * (first_uid==last_uid). An asm feed keeps it alive but adds +2 weighted refs + * (sign 7/39 beats half 7/44 in allocno_compare -> half/sign swapped, closeness 4). + * The dead initializer survives jump/cse (two references), is deleted by flow as a + * dead store before regalloc and never counted, so sign = 5 refs/38 insns + * (10/38=.263) lands exactly between half (14/44=.318) and base (10/50=.2): the + * target's j,mod,i,half,sign,base,arg0 = $s1..$s7 order. match_one MATCH 106/106, + * rtu_match MATCH in the real TU (2026-09-05). + */ +void func_801834A4(s32 arg0) { + + extern s32 D_8018E894[]; + u16 pos[3]; + s32 i; + s32 j; + s32 u; + s32 base; + register s32 tmp __asm__("$2"); + s32 mod; + s32 step; + s32 obj; + s32 half; + register s32 hh __asm__("$2"); + s32 sign = 0; + + if ((D_800B99DA & 7) == 0) { + pos[1] = 0; + pos[2] = 0; + for (i = 0; i < 6; i++) { + u = D_8018E894[i]; + tmp = u * 0x600 + 0x2000; + base = tmp; + __asm__ ("" : "=r"(tmp) : "0"(tmp)); + mod = (tmp << 16) >> 18; + step = u * 6 + 0x12; + half = step * 2; + pos[0] = step; + pos[1] -= 0x24; + for (j = 0; j < 4; j++) { + sign = half >> 31; + obj = func_801850D8(1, (s16)(base + rand() % mod), 0, 0, pos, arg0, + *(s32 *)(((rand() & 1) << 2) + (s32)D_8018E59C), 0); + if (obj != 0) { + *(s32 *)(obj + 0x20) |= 0x800000; + } + hh = half; + pos[0] -= hh / 3; + } + } + } +} + extern s32 rand(void); extern s32 func_801850D8();