mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 14:59:48 -04:00
feat(phase-32): T4b (9) — ov_SC07_002: func_8017DC80 (346 ins) BANKED byte-identical — the historic -33 LENGTH wall's last 46 rows: two combine USE-orphans from reading the s16 mode from memory at each use (§172 producer 2), ONE scratch variable carrying the len byte and the tpage word (the sb's anti-dependence), and a laundered first-statement arg = &D_800AF648 (Fable agent)
- func_8017DC80: draft .run/P32/t5x/fable/func_8017DC80.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_SC07_002 -j8 rc 0; sha1 fad71342019704d1dd6ec25f2f3934c97e322624 == config/check.ov_SC07_002.sha (BYTE-IDENTICAL) - src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c: 2 INCLUDE_ASM left
This commit is contained in:
@@ -3350,7 +3350,405 @@ void func_8017DAEC(void)
|
||||
* D_800A6610[D_800B9A02<<14] + n*4, and chain a DR_TPAGE ((n<<5)&0x9FF)|0xE1000000 when
|
||||
* n<4. Immediates are DECIMAL throughout (maspsx rejects hex in __asm__ strings, §265). */
|
||||
|
||||
INCLUDE_ASM("asm/ov_SC07_002/nonmatchings/ov_SC07_002_jr_8017C8D0", func_8017DC80);
|
||||
/* func_8017DC80 — the D_8019B7B8 record table's POLY_G4 / LINE_G2 emitter.
|
||||
* ov_SC07_002, TU ov_SC07_002_jr_8017C8D0. 346 instructions. MATCH (P32 T5x, fable).
|
||||
*
|
||||
* WHAT IT IS. Ordinary gcc-2.7.2 -O2 C over the PsyQ inline_c.h GTE macros (the
|
||||
* splat "Handwritten function" banner is wrong). It walks the 0xC0-entry
|
||||
* 0x38-stride table at D_8019B7B8; for every record whose low byte is >= 2 it
|
||||
* - RTPTs v3(rec+4, rec+0xC, rec+0x14) + RTPS(rec+0x1C) into a POLY_G4 (0x24),
|
||||
* or RTPTs v3(rec+4, rec+0x14, rec+0x14) into a LINE_G2 (0x14) when the s16
|
||||
* at rec+0x0A (v0.pad, "mode") has bit 0x1000 set,
|
||||
* - biases the OTZ by mode&0xFFF (0xC000 = subtract with clamp-to-0, else add),
|
||||
* - drops it when flag&~0x1000 or otz >= 0x1000,
|
||||
* - fills xy from the stack sxy words and rgb from rec[0x25], rec[0x27],
|
||||
* rec[0x29] (or, when rec+0x34 links a record, that record's colours),
|
||||
* - addPrim()s it into OT bucket D_800A6610[D_800B9A02 << 14] + otz*4 and
|
||||
* chains a DR_TPAGE ((n<<5)&0x9FF)|0xE1000000 in front of it when n < 4.
|
||||
*
|
||||
* LEVERS INHERITED FROM THE T3 OPUS DRAFT (closeness 84 -> 46, see §500-C/D2):
|
||||
* 1. The GTE macros must be REAL macros (this TU's house block, suffixed _2).
|
||||
* 2. §30 /s lattice: plain-scalar sxy frame words, COMPONENT_REF packet stores.
|
||||
* 3. The derived pointers c/va/vb exist as pinned variables (plain r+k makes
|
||||
* loop.c synthesise a fifth induction variable).
|
||||
* 4. The zero-byte `__asm__("" : "=r"(n), "=r"(otz) : "0"(n), "1"(otz))` launder
|
||||
* retires cse1's cross-call unification of the OT index / n<4 test; its two
|
||||
* copies carry identical `#line 900 "p.c"` so jump.c can cross-jump the
|
||||
* POLY/LINE tails (ASM_OPERANDS rtx_equal_p compares file+line) — LOAD-BEARING.
|
||||
*
|
||||
* THE THREE MECHANISMS THAT CLOSED THE LAST 46 ROWS (each read from the -dS/-dR/
|
||||
* .combine/.greg dumps and the compiler source, not guessed):
|
||||
*
|
||||
* A. FRAME 0x70 = TWO combine USE-ORPHANS (§172 producer 2), NOT reload pressure
|
||||
* of a live value. The record's mode halfword is an s16 READ FROM MEMORY at
|
||||
* each use (`*(s16 *)(c - 0x1F) & 0xC000`, and `... & 0xFFF` in each clamp
|
||||
* arm) — there is no `mode` variable. mips.md:2340 extendhisi2 force_not_mem's
|
||||
* the HImode load and promotes through `temp = m<<16; p = temp>>16`; the arm's
|
||||
* `& 0xFFF` is C-shortened to an HImode AND `(and (subreg:SI m) 4095)`, so m has
|
||||
* a second use; combine's 3-way merge makes the `lh` (added_sets_1,
|
||||
* combine.c:1664 keeps m alive) and the ashift `temp` loses its setter —
|
||||
* distribute_notes (combine.c ~10835) walks back to the `bnez flag` jump and
|
||||
* emits `(insn (use (reg temp)))`; reload's alter_reg gives that never-referenced
|
||||
* pseudo an 8-byte slot (align -1) — one per clamp block = +16 bytes at
|
||||
* sp+0x38/0x40 that no instruction touches. The same spelling re-materialises
|
||||
* the HI value as the target's `addu $v1,$v0,$zero` copy instead of an `lhu`.
|
||||
* (An `s16 mode` VARIABLE gives the frame but an `lhu` re-load: 34; an `s32 mode`
|
||||
* variable gives frame 0x60 and no orphan: 46/54.)
|
||||
*
|
||||
* B. THE DR_TPAGE BLOCK: ONE SCRATCH VARIABLE carries BOTH the len byte (1) and
|
||||
* the tpage word. sched.c's backward list scheduler prefers a ready memory
|
||||
* insn at equal priority (schedule_select/potential_hazard), so a `sb` whose
|
||||
* only successor is the tag load is picked right after it — the target instead
|
||||
* places the whole tpage chain first. With `tp = 1; q[3] = tp; ... tp = (n<<5
|
||||
* & 0x9FF) | 0xE1000000; *(u32*)(q+4) = tp;` the `sb` reads the pseudo the
|
||||
* `or` later sets: an ANTI-dependence keeps the `sb` unready until the chain
|
||||
* is placed, `tp` is 2-set (no birthing boost, sched.c adjust_priority), and
|
||||
* both values trivially share `$v1`. `n` must be UNPINNED here: a hard-register
|
||||
* `n` dying at `sll n,5` hands `$s0` to the tpage temp through local-alloc's
|
||||
* dying-input suggestion (combine_regs); an unpinned `n` is a global allocno
|
||||
* that local-alloc never ties, and global.c gives it `$s0` by itself.
|
||||
* (Same idiom, banked: src/800.c:3826-3832.)
|
||||
*
|
||||
* C. `la $a0, D_800AF648` FIRST IN THE PROLOGUE: sched2 is a backward list
|
||||
* scheduler (sched.c schedule_block: each pick is linked BEFORE the previous
|
||||
* one; rank_for_schedule ties -> the highest LUID is picked first), so the body
|
||||
* insn with the LOWEST LUID lands first. The address must therefore be
|
||||
* materialised by the FIRST statement (`arg = &D_800AF648;`) — but combine
|
||||
* substitutes cse's REG_EQUAL constant into the call-site copy and deletes the
|
||||
* first set (measured: identical bytes to the plain call). The zero-byte
|
||||
* `__asm__("" : "=r"(arg) : "0"(arg))` blocks that substitution; the call's
|
||||
* argument copy becomes a no-op and is deleted.
|
||||
*
|
||||
* DECLARATIONS: every symbol is spelled from this target's own relocation lines
|
||||
* and matches the TU (D_8019B7B8 file-scope at L3176, D_800B9A02 at L2468); the
|
||||
* block-scoped externs copy func_80185434's/func_80183FE0's spellings in this
|
||||
* same file, so nothing leaks into the rest of the TU.
|
||||
*/
|
||||
|
||||
#define gte_ldv0_2(r0) __asm__ volatile ( \
|
||||
"lwc2 $0, 0( %0 );" \
|
||||
"lwc2 $1, 4( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) )
|
||||
|
||||
#define gte_ldv3_2(r0, r1, r2) __asm__ volatile (\
|
||||
"lwc2 $0, 0( %0 );" \
|
||||
"lwc2 $1, 4( %0 );" \
|
||||
"lwc2 $2, 0( %1 );" \
|
||||
"lwc2 $3, 4( %1 );" \
|
||||
"lwc2 $4, 0( %2 );" \
|
||||
"lwc2 $5, 4( %2 )" \
|
||||
: \
|
||||
: "r"( r0 ), "r"( r1 ), "r"( r2 ) )
|
||||
|
||||
#define gte_rtps_2() __asm__ volatile ("nop;nop;rtps")
|
||||
#define gte_rtpt_2() __asm__ volatile ("nop;nop;rtpt")
|
||||
#define gte_avsz4_2() __asm__ volatile ("nop;nop;avsz4")
|
||||
|
||||
#define gte_stsxy_2(r0) __asm__ volatile ( \
|
||||
"swc2 $14, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "memory" )
|
||||
|
||||
#define gte_stsxy0_2(r0) __asm__ volatile ( \
|
||||
"swc2 $12, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "memory" )
|
||||
|
||||
#define gte_stsxy1_2(r0) __asm__ volatile ( \
|
||||
"swc2 $13, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "memory" )
|
||||
|
||||
#define gte_stsxy3_2(r0, r1, r2) __asm__ volatile ( \
|
||||
"swc2 $12, 0( %0 );" \
|
||||
"swc2 $13, 0( %1 );" \
|
||||
"swc2 $14, 0( %2 )" \
|
||||
: \
|
||||
: "r"( r0 ), "r"( r1 ), "r"( r2 ) \
|
||||
: "memory" )
|
||||
|
||||
#define gte_stotz_2(r0) __asm__ volatile ( \
|
||||
"swc2 $7, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "memory" )
|
||||
|
||||
#define gte_stszotz_2(r0) __asm__ volatile ( \
|
||||
"mfc2 $12, $19;" \
|
||||
"nop;" \
|
||||
"sra $12, $12, 2;" \
|
||||
"sw $12, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "$12", "memory" )
|
||||
|
||||
#define gte_stflg_2(r0) __asm__ volatile ( \
|
||||
"cfc2 $12, $31;" \
|
||||
"nop;" \
|
||||
"sw $12, 0( %0 )" \
|
||||
: \
|
||||
: "r"( r0 ) \
|
||||
: "$12", "memory" )
|
||||
|
||||
extern s32 D_8019B7B8;
|
||||
|
||||
/* The primitive laid out as a real struct: the COMPONENT_REF stores carry
|
||||
* MEM_IN_STRUCT_P (`/s`) at a VARYING address, the sxy/flag frame slots are plain
|
||||
* non-`/s` scalars at a FIXED address, and sched.c's `/s` drop clause (§30 lattice)
|
||||
* therefore lets each `lw` rise past the previous group's `sh`. LINE_G2 is the
|
||||
* first 0x14 bytes of the same layout. */
|
||||
typedef struct {
|
||||
u8 t0, t1, t2, len; /* 0x00 P_TAG */
|
||||
u8 r0, g0, b0, code; /* 0x04 */
|
||||
s16 x0, y0; /* 0x08 */
|
||||
u8 r1, g1, b1, p1; /* 0x0C */
|
||||
s16 x1, y1; /* 0x10 */
|
||||
u8 r2, g2, b2, p2; /* 0x14 */
|
||||
s16 x2, y2; /* 0x18 */
|
||||
u8 r3, g3, b3, p3; /* 0x1C */
|
||||
s16 x3, y3; /* 0x20 -> 0x24 */
|
||||
} PRIM_8017DC80;
|
||||
|
||||
void func_8017DC80(void)
|
||||
{
|
||||
extern void func_80052E38(void *);
|
||||
extern void *func_80010A08(s32);
|
||||
extern u8 D_800AF648;
|
||||
extern u8 D_800A6610[];
|
||||
extern short D_800B9A02;
|
||||
|
||||
long flag; /* sp+0x10 */
|
||||
long sxy0; /* sp+0x14 */
|
||||
long sxy1; /* sp+0x18 */
|
||||
long sxy2; /* sp+0x1C */
|
||||
long flag2; /* sp+0x20 */
|
||||
long sxy3; /* sp+0x24 */
|
||||
long otzr; /* sp+0x28 */
|
||||
s32 i;
|
||||
|
||||
register u8 *r __asm__("$20");
|
||||
u8 *arg;
|
||||
register u8 *c __asm__("$18");
|
||||
register u8 *va __asm__("$21");
|
||||
register u8 *vb __asm__("$22");
|
||||
u32 ot;
|
||||
s32 n;
|
||||
register u32 otz __asm__("$17");
|
||||
register u32 mlo __asm__("$19"); /* 0x00FFFFFF — P_TAG addr mask */
|
||||
register u32 mhi __asm__("$23");
|
||||
|
||||
u32 *otp;
|
||||
PRIM_8017DC80 *poly;
|
||||
register u8 *q __asm__("$2");
|
||||
register u32 qt __asm__("$5");
|
||||
register u32 ov __asm__("$2");
|
||||
u32 tp;
|
||||
register u32 w __asm__("$3");
|
||||
s32 lo;
|
||||
|
||||
s32 adj;
|
||||
s32 t;
|
||||
u32 cc;
|
||||
|
||||
arg = &D_800AF648;
|
||||
__asm__("" : "=r"(arg) : "0"(arg));
|
||||
r = (u8 *)&D_8019B7B8;
|
||||
mlo = 0xFFFFFF;
|
||||
mhi = 0xFF000000;
|
||||
c = r + 0x29;
|
||||
va = r + 0x14;
|
||||
vb = r + 4;
|
||||
ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];
|
||||
func_80052E38(arg);
|
||||
|
||||
for (i = 0; i < 0xC0; i++) {
|
||||
w = *(u16 *)r;
|
||||
lo = w & 0xFF;
|
||||
if (lo >= 2) {
|
||||
n = w >> 8;
|
||||
if ((*(u16 *)(c - 0x1F) & 0x1000) == 0) {
|
||||
poly = (PRIM_8017DC80 *)func_80010A08(0x24);
|
||||
poly->len = 8; /* setlen(poly, 8) */
|
||||
poly->code = 0x38; /* setcode POLY_G4 */
|
||||
gte_ldv3_2(vb, r + 0xC, va);
|
||||
gte_rtpt_2();
|
||||
gte_stflg_2(&flag);
|
||||
gte_stsxy3_2(&sxy0, &sxy1, &sxy2);
|
||||
gte_ldv0_2(r + 0x1C);
|
||||
gte_rtps_2();
|
||||
gte_stflg_2(&flag2);
|
||||
flag = flag | flag2;
|
||||
gte_stsxy_2(&sxy3);
|
||||
gte_avsz4_2();
|
||||
gte_stotz_2(&otzr);
|
||||
if ((flag & 0xFFFFEFFF) == 0) {
|
||||
otz = otzr;
|
||||
adj = *(s16 *)(c - 0x1F) & 0xC000;
|
||||
if (adj != 0) {
|
||||
if (adj == 0xC000) {
|
||||
otz -= *(s16 *)(c - 0x1F) & 0xFFF;
|
||||
if ((s32)otz < 0) {
|
||||
otz = 0;
|
||||
}
|
||||
} else {
|
||||
otz += *(s16 *)(c - 0x1F) & 0xFFF;
|
||||
}
|
||||
}
|
||||
if (otz < 0x1000) {
|
||||
poly->x0 = sxy0;
|
||||
poly->y0 = sxy0 >> 16;
|
||||
poly->x1 = sxy1;
|
||||
poly->y1 = sxy1 >> 16;
|
||||
poly->x2 = sxy2;
|
||||
poly->y2 = sxy2 >> 16;
|
||||
poly->x3 = sxy3;
|
||||
poly->y3 = sxy3 >> 16;
|
||||
if (*(u32 *)(c + 0xB) != 0) {
|
||||
cc = c[-4];
|
||||
poly->r1 = cc;
|
||||
poly->r0 = cc;
|
||||
cc = c[-2];
|
||||
poly->g1 = cc;
|
||||
poly->g0 = cc;
|
||||
cc = c[0];
|
||||
poly->b1 = cc;
|
||||
poly->b0 = cc;
|
||||
cc = *(u8 *)(*(u32 *)(c + 0xB) + 0x25);
|
||||
poly->r3 = cc;
|
||||
poly->r2 = cc;
|
||||
cc = *(u8 *)(*(u32 *)(c + 0xB) + 0x27);
|
||||
poly->g3 = cc;
|
||||
poly->g2 = cc;
|
||||
cc = *(u8 *)(*(u32 *)(c + 0xB) + 0x29);
|
||||
poly->b3 = cc;
|
||||
poly->b2 = cc;
|
||||
} else {
|
||||
cc = c[-4];
|
||||
poly->r3 = cc;
|
||||
poly->r2 = cc;
|
||||
poly->r1 = cc;
|
||||
poly->r0 = cc;
|
||||
cc = c[-2];
|
||||
poly->g3 = cc;
|
||||
poly->g2 = cc;
|
||||
poly->g1 = cc;
|
||||
poly->g0 = cc;
|
||||
cc = c[0];
|
||||
poly->b3 = cc;
|
||||
poly->b2 = cc;
|
||||
poly->b1 = cc;
|
||||
poly->b0 = cc;
|
||||
}
|
||||
if (n < 4) {
|
||||
poly->code |= 2;
|
||||
}
|
||||
otp = (u32 *)(otz << 2);
|
||||
otp = (u32 *)((u32)otp + ot);
|
||||
*(u32 *)poly = (*(u32 *)poly & mhi) | (*otp & mlo);
|
||||
ov = *otp;
|
||||
*otp = (ov & mhi) | ((u32)poly & mlo);
|
||||
#line 900 "p.c"
|
||||
__asm__ ("" : "=r"(n), "=r"(otz) : "0"(n), "1"(otz));
|
||||
#line 901 "p.c"
|
||||
if (n < 4) {
|
||||
q = (u8 *)func_80010A08(8);
|
||||
tp = 1;
|
||||
q[3] = tp;
|
||||
qt = *(u32 *)q;
|
||||
tp = ((n << 5) & 0x9FF) | 0xE1000000;
|
||||
*(u32 *)(q + 4) = tp;
|
||||
otp = (u32 *)(otz << 2);
|
||||
otp = (u32 *)((u32)otp + ot);
|
||||
*(u32 *)q = (qt & mhi) | (*otp & mlo);
|
||||
*otp = (*otp & mhi) | ((u32)q & mlo);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poly = (PRIM_8017DC80 *)func_80010A08(0x14);
|
||||
poly->len = 4; /* setlen(poly, 4) */
|
||||
poly->code = 0x50; /* setcode LINE_G2 */
|
||||
gte_ldv3_2(vb, va, va);
|
||||
gte_rtpt_2();
|
||||
gte_stsxy0_2(&sxy0);
|
||||
gte_stsxy1_2(&sxy1);
|
||||
gte_stflg_2(&flag);
|
||||
gte_stszotz_2(&otzr);
|
||||
if ((flag & 0xFFFFEFFF) == 0) {
|
||||
otz = otzr;
|
||||
adj = *(s16 *)(c - 0x1F) & 0xC000;
|
||||
if (adj != 0) {
|
||||
if (adj == 0xC000) {
|
||||
otz -= *(s16 *)(c - 0x1F) & 0xFFF;
|
||||
if ((s32)otz < 0) {
|
||||
otz = 0;
|
||||
}
|
||||
} else {
|
||||
otz += *(s16 *)(c - 0x1F) & 0xFFF;
|
||||
}
|
||||
}
|
||||
if (otz < 0x1000) {
|
||||
poly->x0 = sxy0;
|
||||
poly->y0 = sxy0 >> 16;
|
||||
poly->x1 = sxy1;
|
||||
poly->y1 = sxy1 >> 16;
|
||||
if (*(u32 *)(c + 0xB) != 0) {
|
||||
poly->r0 = c[-4];
|
||||
poly->g0 = c[-2];
|
||||
poly->b0 = c[0];
|
||||
poly->r1 = *(u8 *)(*(u32 *)(c + 0xB) + 0x25);
|
||||
poly->g1 = *(u8 *)(*(u32 *)(c + 0xB) + 0x27);
|
||||
poly->b1 = *(u8 *)(*(u32 *)(c + 0xB) + 0x29);
|
||||
} else {
|
||||
cc = c[-4];
|
||||
poly->r1 = cc;
|
||||
poly->r0 = cc;
|
||||
cc = c[-2];
|
||||
poly->g1 = cc;
|
||||
poly->g0 = cc;
|
||||
cc = c[0];
|
||||
poly->b1 = cc;
|
||||
poly->b0 = cc;
|
||||
}
|
||||
if (n < 4) {
|
||||
poly->code |= 2;
|
||||
}
|
||||
otp = (u32 *)(otz << 2);
|
||||
otp = (u32 *)((u32)otp + ot);
|
||||
*(u32 *)poly = (*(u32 *)poly & mhi) | (*otp & mlo);
|
||||
ov = *otp;
|
||||
*otp = (ov & mhi) | ((u32)poly & mlo);
|
||||
#line 900 "p.c"
|
||||
__asm__ ("" : "=r"(n), "=r"(otz) : "0"(n), "1"(otz));
|
||||
#line 901 "p.c"
|
||||
if (n < 4) {
|
||||
q = (u8 *)func_80010A08(8);
|
||||
tp = 1;
|
||||
q[3] = tp;
|
||||
qt = *(u32 *)q;
|
||||
tp = ((n << 5) & 0x9FF) | 0xE1000000;
|
||||
*(u32 *)(q + 4) = tp;
|
||||
otp = (u32 *)(otz << 2);
|
||||
otp = (u32 *)((u32)otp + ot);
|
||||
*(u32 *)q = (qt & mhi) | (*otp & mlo);
|
||||
*otp = (*otp & mhi) | ((u32)q & mlo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c += 0x38;
|
||||
va += 0x38;
|
||||
vb += 0x38;
|
||||
r += 0x38;
|
||||
}
|
||||
}
|
||||
#line 3360 "src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c"
|
||||
|
||||
|
||||
|
||||
extern s32 D_8019B7B8;
|
||||
|
||||
Reference in New Issue
Block a user