mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-30 07:31:59 -04:00
feat(phase-32): T4b (6) — ov_SC03_105: func_801834A4 (106 ins) BANKED byte-identical — a pinned WALL falls: a CSE-quantity split hoists only the division's sign correction (sign = half >> 31 at the loop top; the divide reads a hard-register copy so its mult is not a movable; expand_divmod's sra is CSE'd into sign) (Fable agent)
- 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
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user