From 4792daaaef8163c594fb133f98fd60841a8a64c5 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Fri, 11 Sep 2026 03:53:34 -0600 Subject: [PATCH] =?UTF-8?q?phase-36:=20S104=20s104=5Fe22=20=E2=80=94=20fun?= =?UTF-8?q?c=5F8017C954=20banked=20at=200=20through=20the=20whole-object?= =?UTF-8?q?=20gate=20+=20propagated=20=E2=80=94=20barrier=20=E2=86=92=200:?= =?UTF-8?q?=20a=20reused=20value=20split=20into=20s16=20wq=20(local-alloc.?= =?UTF-8?q?c:472;=20sched.c:2469-2490)=20+=20g.opz=20in=20both=20arms=20(a?= =?UTF-8?q?n=20integer=20tie,=20global.c:594-607)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agents/ov_SC06_029__func_8017C954/body.c | 445 ++++++++++++++++++ .../ov_SC06_029__func_8017C954/mechanism.md | 89 ++++ .../agents/ov_SC06_029__func_80181708/body.c | 19 + .../ov_SC06_029__func_80181708/mechanism.md | 69 +++ .../agents/ov_SC06_029__func_80184EFC/body.c | 34 ++ .../ov_SC06_029__func_80184EFC/mechanism.md | 58 +++ .../agents/ov_SC06_029__func_80185D44/body.c | 33 ++ .../ov_SC06_029__func_80185D44/mechanism.md | 59 +++ .run/P36/delever/calibration.json | 374 +++++++-------- .run/P36/delever/ledger.jsonl | 1 + src/ov_SC06_029/ov_SC06_029_jr_8017C954.c | 17 +- 11 files changed, 1002 insertions(+), 196 deletions(-) create mode 100644 .run/P36/agents/ov_SC06_029__func_8017C954/body.c create mode 100644 .run/P36/agents/ov_SC06_029__func_8017C954/mechanism.md create mode 100644 .run/P36/agents/ov_SC06_029__func_80181708/body.c create mode 100644 .run/P36/agents/ov_SC06_029__func_80181708/mechanism.md create mode 100644 .run/P36/agents/ov_SC06_029__func_80184EFC/body.c create mode 100644 .run/P36/agents/ov_SC06_029__func_80184EFC/mechanism.md create mode 100644 .run/P36/agents/ov_SC06_029__func_80185D44/body.c create mode 100644 .run/P36/agents/ov_SC06_029__func_80185D44/mechanism.md diff --git a/.run/P36/agents/ov_SC06_029__func_8017C954/body.c b/.run/P36/agents/ov_SC06_029__func_8017C954/body.c new file mode 100644 index 000000000..8558f43f0 --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_8017C954/body.c @@ -0,0 +1,445 @@ +void func_8017C954(s32 arg0) +{ + typedef struct { u32 w0, w1, w2; } Prim; + + extern s32 func_800491EC(void); + extern void func_800547D8(s32, MATRIX2 *); + extern void func_80052E38(MATRIX2 *); + extern u8 *D_800A5E60; + extern u8 D_800A6610[]; + extern short D_800B9A02; /* TU-visible spelling (engine_core.h + ov_SC01_000.c col-0); unsigned access forced at use — §8d sub-class (b) */ + extern s32 D_801DCCA0; /* fade/flash level driving both overlay colours */ + + DVECTOR2 tmpxy[4]; + SVECTOR2 box[8]; + SVECTOR2 sxy[8]; + SVECTOR2 vv[4]; /* 0xA0..0xBF; only vv[3] is used (arm E vertex copy) */ + MATRIX2 mtx; + struct { long otz, flag, opz, sz0, sz1, sz2, sz3; } g; + + s32 lim; + u32 colA; + u32 colB; + u32 nprim; + s32 nparts; + s32 j; + u32 i; + Part *part; + Prim *prim; + u8 *pkt; + u32 ot; + u8 *vtx; + u8 *va, *vb, *vc, *vd; + u32 w, code; + u32 wx, wy, wz; + s16 wq; /* P36 S104 e22: the box's high z half, its own s16 (see mechanism.md) */ + s32 xa32, xb32, t32; + s32 xmn1, xmx1, xmn2, xmx2; + s32 mnc, mxc; + s16 my, mny, mx, mn; + s32 d; + u32 e; + + lim = func_800491EC() + *(s32 *)(arg0 + 0x64); + func_800547D8(arg0 + 0x10, &mtx); + func_80052E38(&mtx); + + pkt = D_800A5E60; + ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14]; + d = D_801DCCA0; + colA = (d << 16) | (d << 8) | d; + e = d * 2; + if (e > 0xFF) e = 0xFF; + colB = (e << 16) | (e << 8) | e; + part = *(Part **)(arg0 + 0xC); + nparts = *(s32 *)(*(s32 *)(arg0 + 8) + 8); + vtx = *(u8 **)(*(s32 *)(arg0 + 8) + 0x10); + + for (j = 0; j < nparts; j++, part++) { + wx = part->xx; + mn = wx; + mx = wx >> 16; + wy = part->yy; + mny = wy; + my = wy >> 16; + wz = part->zz; + box[0].vx = mn; box[0].vy = mny; + box[1].vx = mx; box[1].vy = mny; + box[2].vx = mn; box[2].vy = mny; + box[3].vx = mx; box[3].vy = mny; + box[4].vx = mn; box[4].vy = my; + box[5].vx = mx; box[5].vy = my; + box[6].vx = mn; box[6].vy = my; + box[7].vx = mx; box[7].vy = my; + wq = wz >> 16; + box[0].vz = wz; + box[1].vz = wz; + box[4].vz = wz; + box[5].vz = wz; + box[2].vz = wq; + box[3].vz = wq; + box[6].vz = wq; + box[7].vz = wq; + + gte_ldv3c(&box[0]); + gte_rtpt(); + gte_stsxy3(&sxy[0], &sxy[1], &sxy[2]); + gte_ldv0(&box[3]); + gte_rtps(); + gte_stsxy(&sxy[3]); + gte_ldv3c(&box[4]); + gte_rtpt(); + gte_stsxy3(&sxy[4], &sxy[5], &sxy[6]); + gte_ldv0(&box[7]); + gte_rtps(); + gte_stsxy(&sxy[7]); + gte_stszotz(&g.otz); + + if (lim >= g.otz) { + xa32 = sxy[0].vx; + xb32 = sxy[1].vx; + if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; } + t32 = sxy[2].vx; + if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32; + t32 = sxy[3].vx; + if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32; + xa32 = sxy[4].vx; + xb32 = sxy[5].vx; + if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; } + t32 = sxy[6].vx; + if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32; + t32 = sxy[7].vx; + if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32; + mnc = xmn1; + if (xmn2 < xmn1) mnc = xmn2; + mxc = xmx1; + if (mxc < xmx2) mxc = xmx2; + if ((s16)mxc >= -0xA0 && (s16)mnc < 0xA1) { + xa32 = sxy[0].vy; + xb32 = sxy[1].vy; + if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; } + t32 = sxy[2].vy; + if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32; + t32 = sxy[3].vy; + if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32; + xa32 = sxy[4].vy; + xb32 = sxy[5].vy; + if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; } + t32 = sxy[6].vy; + if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32; + t32 = sxy[7].vy; + if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32; + mnc = xmn1; + if (xmn2 < xmn1) mnc = xmn2; + mxc = xmx1; + if (mxc < xmx2) mxc = xmx2; + if ((s16)mxc >= -0x78 && (s16)mnc < 0x79) { + prim = (Prim *)part->prim; + nprim = part->nprim; + for (i = 0; i < nprim; i++, prim++) { + w = prim->w1; + va = vtx + (w & 0xFFFF); + vb = vtx + (w >> 16); + w = prim->w2; + vc = vtx + (w & 0xFFFF); + w = w >> 16; + gte_ldv3(va, vb, vc); + gte_rtpt(); + gte_stflg(&g.flag); + if (!(g.flag & 0x7F85E000)) { + gte_nclip(); + code = w & 7; + vd = vtx + (w & 0xFFF8); + gte_stopz(&g.opz); + if (g.opz > 0) { + switch (code) { + case 4: + case 5: + gte_stsxy3_f3(pkt); + gte_stsz3(&g.sz0, &g.sz1, &g.sz2); + if (((PolyF3 *)pkt)->x0 > ((PolyF3 *)pkt)->x1) { + mx = ((PolyF3 *)pkt)->x0; + mn = ((PolyF3 *)pkt)->x1; + } else { + mn = ((PolyF3 *)pkt)->x0; + mx = ((PolyF3 *)pkt)->x1; + } + if (((PolyF3 *)pkt)->x2 > mx) mx = ((PolyF3 *)pkt)->x2; + else if (((PolyF3 *)pkt)->x2 < mn) mn = ((PolyF3 *)pkt)->x2; + if (mx >= -0xA0 && mn < 0xA1) { + if (((PolyF3 *)pkt)->y0 > ((PolyF3 *)pkt)->y1) { + my = ((PolyF3 *)pkt)->y0; + mny = ((PolyF3 *)pkt)->y1; + } else { + mny = ((PolyF3 *)pkt)->y0; + my = ((PolyF3 *)pkt)->y1; + } + if (((PolyF3 *)pkt)->y2 > my) my = ((PolyF3 *)pkt)->y2; + else if (((PolyF3 *)pkt)->y2 < mny) mny = ((PolyF3 *)pkt)->y2; + if (my >= -0x78 && mny < 0x79) { + s32 za, zb; + u32 *otp; + if (g.sz0 > g.sz1) { + za = g.sz0; + if (za < g.sz2) za = g.sz2; + } else { + za = g.sz1; + if (za < g.sz2) za = g.sz2; + } + g.opz = za; + if (code != 4) g.opz = za + 0x200; + ((PolyF3 *)pkt)->rgbc = prim->w0; + otp = (u32 *)(((g.opz >> 2) << 2) + ot); + *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x4000000; + *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + pkt += 0x14; + } + } + break; + case 6: + case 7: + gte_stsxy3_ft3(pkt); + gte_stsz3(&g.sz0, &g.sz1, &g.sz2); + if (((PolyFT3 *)pkt)->x0 > ((PolyFT3 *)pkt)->x1) { + mx = ((PolyFT3 *)pkt)->x0; + mn = ((PolyFT3 *)pkt)->x1; + } else { + mn = ((PolyFT3 *)pkt)->x0; + mx = ((PolyFT3 *)pkt)->x1; + } + if (((PolyFT3 *)pkt)->x2 > mx) mx = ((PolyFT3 *)pkt)->x2; + else if (((PolyFT3 *)pkt)->x2 < mn) mn = ((PolyFT3 *)pkt)->x2; + if (mx >= -0xA0 && mn < 0xA1) { + if (((PolyFT3 *)pkt)->y0 > ((PolyFT3 *)pkt)->y1) { + my = ((PolyFT3 *)pkt)->y0; + mny = ((PolyFT3 *)pkt)->y1; + } else { + mny = ((PolyFT3 *)pkt)->y0; + my = ((PolyFT3 *)pkt)->y1; + } + if (((PolyFT3 *)pkt)->y2 > my) my = ((PolyFT3 *)pkt)->y2; + else if (((PolyFT3 *)pkt)->y2 < mny) mny = ((PolyFT3 *)pkt)->y2; + if (my >= -0x78 && mny < 0x79) { + s32 za, zb; + u32 *otp; + u32 *tp; + if (g.sz0 > g.sz1) { + za = g.sz0; + if (za < g.sz2) za = g.sz2; + g.opz = za; + } else { + za = g.sz1; + if (za < g.sz2) za = g.sz2; + g.opz = za; + } + if (code == 7) g.opz = za + 0x200; + tp = (u32 *)prim->w0; + ((PolyFT3 *)pkt)->rgbc = tp[0]; + ((PolyFT3 *)pkt)->uvc0 = tp[1]; + ((PolyFT3 *)pkt)->uvp1 = tp[2]; + ((PolyFT3 *)pkt)->uv2 = tp[3]; + otp = (u32 *)(((g.opz >> 2) << 2) + ot); + *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x7000000; + *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + pkt += 0x20; + } + } + break; + case 0: + case 1: + gte_stsxy3_f3(pkt); + gte_ldv0(vd); + gte_rtps(); + if (((PolyF4 *)pkt)->x0 > ((PolyF4 *)pkt)->x1) { + mx = ((PolyF4 *)pkt)->x0; + mn = ((PolyF4 *)pkt)->x1; + } else { + mn = ((PolyF4 *)pkt)->x0; + mx = ((PolyF4 *)pkt)->x1; + } + if (((PolyF4 *)pkt)->x2 > mx) mx = ((PolyF4 *)pkt)->x2; + else if (((PolyF4 *)pkt)->x2 < mn) mn = ((PolyF4 *)pkt)->x2; + if (((PolyF4 *)pkt)->y0 > ((PolyF4 *)pkt)->y1) { + my = ((PolyF4 *)pkt)->y0; + mny = ((PolyF4 *)pkt)->y1; + } else { + mny = ((PolyF4 *)pkt)->y0; + my = ((PolyF4 *)pkt)->y1; + } + if (((PolyF4 *)pkt)->y2 > my) my = ((PolyF4 *)pkt)->y2; + else if (((PolyF4 *)pkt)->y2 < mny) mny = ((PolyF4 *)pkt)->y2; + gte_stflg(&g.flag); + if (!(g.flag & 0x7F85E000)) { + gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3); + gte_stsxy((long *)&((PolyF4 *)pkt)->x3); + if (((PolyF4 *)pkt)->x3 < mn) mn = ((PolyF4 *)pkt)->x3; + else if (mx < ((PolyF4 *)pkt)->x3) mx = ((PolyF4 *)pkt)->x3; + if (mx >= -0xA0 && mn < 0xA1) { + if (((PolyF4 *)pkt)->y3 < mny) mny = ((PolyF4 *)pkt)->y3; + else if (my < ((PolyF4 *)pkt)->y3) my = ((PolyF4 *)pkt)->y3; + if (my >= -0x78 && mny < 0x79) { + s32 za, zb; + u32 *otp; + zb = g.sz2; + if (zb < g.sz3) zb = g.sz3; + za = g.sz0; + if (za < g.sz1) za = g.sz1; + if (za < zb) za = zb; + g.opz = za; + ((PolyF4 *)pkt)->rgbc = prim->w0; + otp = (u32 *)(((za >> 2) << 2) + ot); + *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x5000000; + *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + pkt += 0x18; + } + } + } + break; + case 2: + gte_stsxy3c(&tmpxy[0]); + gte_ldv0(vd); + gte_rtps(); + if (tmpxy[0].vx > tmpxy[1].vx) { + mx = tmpxy[0].vx; + mn = tmpxy[1].vx; + } else { + mn = tmpxy[0].vx; + mx = tmpxy[1].vx; + } + if (tmpxy[2].vx > mx) mx = tmpxy[2].vx; + else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx; + if (tmpxy[0].vy > tmpxy[1].vy) { + my = tmpxy[0].vy; + mny = tmpxy[1].vy; + } else { + mny = tmpxy[0].vy; + my = tmpxy[1].vy; + } + if (tmpxy[2].vy > my) my = tmpxy[2].vy; + else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy; + gte_stflg(&g.flag); + if (!(g.flag & 0x7F85E000)) { + gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3); + gte_stsxy((long *)&((PolyFT4 *)pkt)->x3); + if (((PolyFT4 *)pkt)->x3 < mn) mn = ((PolyFT4 *)pkt)->x3; + else if (mx < ((PolyFT4 *)pkt)->x3) mx = ((PolyFT4 *)pkt)->x3; + if (mx >= -0xA0 && mn < 0xA1) { + if (((PolyFT4 *)pkt)->y3 < mny) mny = ((PolyFT4 *)pkt)->y3; + else if (my < ((PolyFT4 *)pkt)->y3) my = ((PolyFT4 *)pkt)->y3; + if (my >= -0x78 && mny < 0x79) { + s32 za, zb; + u32 *otp; + u32 *tp; + u32 uvw; + zb = g.sz2; + if (zb < g.sz3) zb = g.sz3; + za = g.sz0; + if (za < g.sz1) za = g.sz1; + if (za < zb) za = zb; + g.opz = za; + if (code == 3) g.opz = za + 0x200; + *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0]; + *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1]; + *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2]; + tp = (u32 *)prim->w0; + ((PolyFT4 *)pkt)->rgbc = tp[0]; + ((PolyFT4 *)pkt)->uvc0 = tp[1]; + ((PolyFT4 *)pkt)->uvp1 = tp[2]; + uvw = tp[3]; + ((PolyFT4 *)pkt)->uv2 = uvw; + ((PolyFT4 *)pkt)->uv3 = uvw >> 16; + otp = (u32 *)(((g.opz >> 2) << 2) + ot); + *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x9000000; + *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + pkt += 0x28; + } + } + } + break; + case 3: + gte_stsxy3c(&tmpxy[0]); + vv[3] = *(SVECTOR2 *)vd; + gte_ldv0(&vv[3]); + gte_rtps(); + if (tmpxy[0].vx > tmpxy[1].vx) { + mx = tmpxy[0].vx; + mn = tmpxy[1].vx; + } else { + mn = tmpxy[0].vx; + mx = tmpxy[1].vx; + } + if (tmpxy[2].vx > mx) mx = tmpxy[2].vx; + else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx; + if (tmpxy[0].vy > tmpxy[1].vy) { + my = tmpxy[0].vy; + mny = tmpxy[1].vy; + } else { + mny = tmpxy[0].vy; + my = tmpxy[1].vy; + } + if (tmpxy[2].vy > my) my = tmpxy[2].vy; + else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy; + gte_stflg(&g.flag); + if (!(g.flag & 0x7F85E000)) { + gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3); + gte_stsxy((long *)&tmpxy[3]); + if (tmpxy[3].vx < mn) mn = tmpxy[3].vx; + else if (mx < tmpxy[3].vx) mx = tmpxy[3].vx; + if (mx >= -0xA0 && mn < 0xA1) { + if (tmpxy[3].vy < mny) mny = tmpxy[3].vy; + else if (my < tmpxy[3].vy) my = tmpxy[3].vy; + if (my >= -0x78 && mny < 0x79) { + s32 za, zb; + u32 *otp; + u32 *tp; + u32 uvw; + zb = g.sz2; + if (zb < g.sz3) zb = g.sz3; + za = g.sz0; + if (za < g.sz1) za = g.sz1; + if (za < zb) za = zb; + g.opz = za; + *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0]; + *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1]; + *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2]; + *(u32 *)&((PolyFT4 *)pkt)->x3 = *(u32 *)&tmpxy[3]; + tp = (u32 *)prim->w0; + ((PolyFT4 *)pkt)->rgbc = colA | 0x2E000000; + ((PolyFT4 *)pkt)->uvc0 = tp[1]; + ((PolyFT4 *)pkt)->uvp1 = tp[2]; + uvw = tp[3]; + ((PolyFT4 *)pkt)->uv2 = uvw; + ((PolyFT4 *)pkt)->uv3 = uvw >> 16; + { + u32 *op1 = (u32 *)(((za >> 2) << 2) + ot); + *(u32 *)pkt = (*op1 & 0xFFFFFF) | 0x9000000; + *op1 = (*op1 & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + } + pkt += 0x28; + pkt[3] = 6; + *(u32 *)(pkt + 8) = colB | 0x2A000000; + *(u32 *)(pkt + 0xC) = *(u32 *)&tmpxy[0]; + *(u32 *)(pkt + 4) = 0xE1000040; + *(u32 *)(pkt + 0x10) = *(u32 *)&tmpxy[1]; + *(u32 *)(pkt + 0x14) = *(u32 *)&tmpxy[2]; + *(u32 *)(pkt + 0x18) = *(u32 *)&tmpxy[3]; + { + u32 *op2 = (u32 *)(((g.opz >> 2) << 2) + ot); + *(u32 *)pkt = (*op2 & 0xFFFFFF) | 0x6000000; + *op2 = (*op2 & 0xFF000000) | ((u32)pkt & 0xFFFFFF); + } + pkt += 0x1C; + } + } + } + break; + } + } + } + } + } + } + } + } + D_800A5E60 = pkt; +} diff --git a/.run/P36/agents/ov_SC06_029__func_8017C954/mechanism.md b/.run/P36/agents/ov_SC06_029__func_8017C954/mechanism.md new file mode 100644 index 000000000..2efcdb49f --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_8017C954/mechanism.md @@ -0,0 +1,89 @@ +# func_8017C954 (ov_SC06_029) — agent e22, P36 S104 + +**Result: score 0, ZERO levers (the `__asm__ __volatile__ ("" ::: "$3")` "L1 dial" is gone). Levers 1 -> 0.** +Two plain-C edits to body_free.c (1194 = 1194 ins): +1. the box's second use of `wy` (`wy = wz >> 16;`, the high z half) becomes its own local `s16 wq;`; +2. in arm B (case 6/7, PolyFT3) `g.opz = za;` is written inside BOTH branches of the za max-of-3 instead of once after + the if/else (the spelling the lever-free family members ov_SC03_014 func_8017DF84 :4812 and func_8017FA5C :3410 + already use in the same FT3 arm). +The function's file-level header (L1 dial, L6 "zero sliders") describes the old levers and should be rewritten when +this banks (I did not edit it — outside the body). + +## (a) The residual +Lever-free: 632 (COUNT, 1182 vs 1194). The header's diagnosis was right about the symptom: the s16 quad +my/mny/mx/mn slides one slot down reg_alloc_order (v1,a2,a3,t0 instead of a2,a3,t0,t1), which renames ~40% of every +switch arm and changes the spill count (frame 656 vs 664, -12 ins). + +## (b) The passes and decisions (all proven on bytes/dumps) +Step 1 — why my/mny take $v1: +- `wy` holds TWO values (`part->yy`, later `wz >> 16`) -> dies in 2 places -> refused by local-alloc + (`reg_n_deaths == 1`, local-alloc.c:472) -> a GLOBAL allocno. So no LOCAL pseudo in $v1 is live while my/mny are: + my/mny have no hard conflict with $v1 (`;; 103 conflicts: ... 2 12 29`) and keep a $v1 preference, which + `prune_preferences` (global.c:834-874) only deletes for a conflicting register; my takes $v1 (find_reg's preference + pass, global.c:1037-1071) and, via `regs_someone_prefers`, every earlier per-arm HI temp (r277, r360, ...) is pushed + from $v1 to $a0 — the cascade (r277 identical conflicts in both compiles, different register: a0 vs v1). +- With `wq` its own variable, `wy` is single-value -> local ($v1), and `wq` is local too. Its WIDTH is what matters: + as `s16` the shift is `(set (subreg:SI (reg:HI wq) 0) (lshiftrt ...))` — a SUBREG destination, so + `birthing_insn_p` (sched.c:2469-2490) fails and sched1 keeps the shift early (right after `my = wy >> 16`), while + the `box[].vz = wz` stores still follow: `wz` stays live, `wq` cannot tie to it, local-alloc gives `wq` $v1 for a + stretch where all four of my/mny/mx/mn are live -> each gets a HARD conflict with $v1 (`;; 104..107 conflicts: + 2 3 12 29`) -> the quad lands on a2/a3/t0/t1, exactly the tree's asm clobber, but for a real reason. + As `u32 wq` the set is a REG, gets the birthing boost, is scheduled after the wz stores, ties to wz's $v0 and the + conflict never appears (gen_box.py: 459; s16/u16: 28). +Step 2 — the last 28 (header L6: the 3-cycle {vtx, &g.flag, 0x7F85E000} and the {&g.sz1, &g.sz2} swap): +- Every loop-invariant allocno's live length (recomputed by sched1, sched.c:4911-4947) was exactly ONE insn shorter + than with the tree's zero-byte asm: &g.sz{1,2,3} 967/968/969 -> `allocno_compare` (global.c:594-607) + floor(640000/L) = 661/661/660 — a TIE, broken by allocno number the wrong way (tree: 968/969/970 -> 661/660/659); + same for &g.flag vs the constant (390000/L). +- A diagnostic `__asm__("")` probe (not delivered) at each of 267 statement positions gave 0 at 138 of them: ANY + one zero-byte insn inside the outer loop is the whole residual. +- The plain-C source of that insn: `g.opz = za;` duplicated into both branches is TWO stores through allocation + (9 `sw ...,232(sp)` in `.greg`) and ONE in the bytes (8 in `.jump2`/`.dbr`/objdump): the post-reload jump pass's + cross-jump (`find_cross_jump`, jump.c:2371, run from toplev.c after reload) merges the identical tails, so the bytes + are unchanged and every live range through arm B is one insn longer. Duplicating it in arms A AND B is +2 -> 115; + either arm alone -> 0; arm B chosen because the family's lever-free members spell arm B that way. + (Found by running the R2-R41 recipe families (`tools/delever.py recipe_candidates`, read-only import) over the + 28-body: 1,655 candidates, exactly two at 0 — R39 dup-join in arm A and in arm B.) + +## (c) The moves +1. `s16 wq; ... wq = wz >> 16; box[2/3/6/7].vz = wq;` (632 -> 28) +2. arm B: `if (g.sz0 > g.sz1) { za = g.sz0; if (za < g.sz2) za = g.sz2; g.opz = za; } else { ...; g.opz = za; }` + (28 -> 0) +Both single-step scores are better than the start; neither alone closes. + +## (d) Generator proposals +- R-WIDTH-SPLIT: when a local is assigned twice (two unrelated values, "dies in 2 places" in `.lreg`) and one value + is a narrowing `x >> 16` / truncation stored to 16-bit fields, split that value into its own local AT THE FIELD + WIDTH (s16/u16): the SUBREG destination removes sched1's birthing boost, keeping the definition where the reused + variable had it (a u32 split is a different schedule). +- R39 dup-join as a LIVE-LENGTH dial: when a register residual is a permutation among long-lived loop invariants whose + `alloc_table` priorities TIE (or sit 1 apart), and a zero-byte `asm("")` probe anywhere in the loop closes it, try + R39 (duplicate a join-point store into both arms) — cross-jump removes the copy post-reload, so it is +1 live length + at zero bytes. Tooling: an `asm("")` position probe is a cheap oracle for "is the residual a live-length off-by-one". + +## (e) Tried and failed (bytes) +- per-arm / per-box scoping of my/mny/mx/mn (64 variants, gen_scope.py): best 503. +- wq as u32 in 36 placements/store orders/assignment orders (gen_box.py): best 459 (my first, `my = wy >> 16;`). +- wq s16/u16: 28 in every placement tried; comparison operand flips on all 84 ifs (gen_flip.py): all 28 (the front + end canonicalises them). +- dup-join in arms A and B together: 115. +- The earlier `$3` dial and the header's "six natural spellings" are superseded; the header's L2-L5 moves are already + in body_free and stay. + +## (f) Where the method fell short +- The regen sweep (s104_all) was run on the 632 body; its best (581) never met R39 because the dial's residual hid + behind the big slide. Re-running the generator families AFTER a structural fix found the finisher in one pass — + the sweep should be re-run on every agent's improved body, not only the free one. +- alloc_table.py prints preferences only after pruning; the $v1 preference that drove the slide was invisible in the + tree's dump (pruned by the clobber's conflict). A "preferences before prune" column would have shown it. +- Sibling ov_SC06_000 func_8017EF68 (same family, one launder on `wq`): `s16 wq` there scores 14 = its lever-free + score (scratch/sib/) — a different residual (a sched order), not closed by this text. + +Scratch kept (scratch/c/keep/): dupjoin_armB.c (= body.c before the comment clean-up), dupjoin_armA.c (also 0), +dupjoin_AB_115.c, wq_s16_28.c, wq_u32_459.c; generators gen_box.py / gen_box2.py / gen_scope.py / gen_flip.py / +regen.py; dump helpers quick.sh, annot.py (RTL with each pseudo's local/global hard reg), regmap.py, live.py. + +## (g) Structs +Not the channel here: the decisions are local-alloc eligibility (a reused variable), sched1's birthing rule (the +declared width of a local), and a post-reload cross-jump. The Part/Prim/POLY_* accesses already go through struct +types; turning `g` into a named struct or `tmpxy` into DVECTOR changes nothing these passes look at. diff --git a/.run/P36/agents/ov_SC06_029__func_80181708/body.c b/.run/P36/agents/ov_SC06_029__func_80181708/body.c new file mode 100644 index 000000000..3165dd713 --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80181708/body.c @@ -0,0 +1,19 @@ +void func_80181708(int param_1) { + typedef struct { s16 vx, vy, vz, pad; } SV; + typedef struct { u8 pad[0x3C]; s32 x3C; s32 x40; s32 x44; s32 x48; s32 x4C; s32 x50; } OB; + extern s16 D_801904C6_a[] __asm__("D_801904C6"); + extern s16 D_801904CE_a[] __asm__("D_801904CE"); + SV *p1 = (SV *)D_801DFD8C; + SV *p2 = (SV *)D_801DFD90; + + ((OB *)param_1)->x48 = p1->vx; + ((OB *)param_1)->x50 = p1->vz; + ((OB *)param_1)->x3C = p2->vx; + ((OB *)param_1)->x44 = p2->vz; + ((OB *)param_1)->x4C += (s16)func_80012CB8(D_801904C6_a[0], p1->vy, 0xC0); + ((OB *)param_1)->x40 += (s16)func_80012CB8(D_801904CE_a[0], ((SV *)D_801DFD90)->vy, 0xC0); + if (((OB *)param_1)->x4C < ((SV *)D_801DFD8C)->vy) + ((OB *)param_1)->x4C = ((SV *)D_801DFD8C)->vy; + if (((OB *)param_1)->x40 < ((SV *)D_801DFD90)->vy) + ((OB *)param_1)->x40 = ((SV *)D_801DFD90)->vy; +} diff --git a/.run/P36/agents/ov_SC06_029__func_80181708/mechanism.md b/.run/P36/agents/ov_SC06_029__func_80181708/mechanism.md new file mode 100644 index 000000000..2dad4d85a --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80181708/mechanism.md @@ -0,0 +1,69 @@ +# func_80181708 (ov_SC06_029) — agent e22, P36 S104 + +**Result: score 0, ZERO levers (the $3 pin and the `__asm__("")` barrier both gone). Levers 2 -> 0.** +The body uses two body-local STRUCT typedefs (`SV` = {vx,vy,vz,pad} for the two SVECTOR-pointer globals, `OB` for the +object at `param_1`) and two body-local array-typed DECLARATION aliases of the s16 globals +(`extern s16 D_801904C6_a[] __asm__("D_801904C6");`, same for `D_801904CE`). No pin, no asm statement, no volatile, +no signature change. The file-scope equivalent of the aliases is `extern s16 D_801904C6[];` / `D_801904CE[]` in the TU +(a declaration-type change outside the body — the STRUCTS phase can make it and drop the aliases). + +## (a) The residual +Lever-free: score 26 (COUNT, 66 vs 65). Two independent defects: +1. block 0: `psVar1`/`psVar2` land in v1/a0 where the target has a1/v1; with psVar2 in a0 sched2 cannot hoist its load + above `move s0,a0`, so the prologue interleave differs (+1 ins). +2. after call 1: sched1 order `sll, sra, lw 76, lw t, addu, sw` vs the target's `sll, lw 76, sra, addu, lw t, sw`, so + the reloaded `D_801DFD90` (t) is born while the `sra` result still holds v0 and takes a1 instead of v0. + +## (b) The pass and the decision (read, then proven on bytes) +- sched.c:817-839 `true_dependence` / :845-861 `anti_dependence`: a MEM_IN_STRUCT access at a VARYING address never + conflicts with a NON-struct access at a FIXED address. expr.c:4568-4577 sets MEM_IN_STRUCT for an INDIRECT_REF of a + PLUS_EXPR or an aggregate; `*(s32 *)(param_1 + K)` is a NOP_EXPR of an int sum -> NOT struct; `((OB *)param_1)->xK` + -> struct; `D_801DFD8C` (s32 scalar) -> non-struct fixed; `D_801904C6` as `s16` -> non-struct fixed, as `s16[]` + element -> struct fixed. +- With the stores struct-varying, the loads of the two pointer globals (non-struct fixed) lose every memory edge: + sched1 (backward, birthing boost sched.c:2469-2544 since each is set once) places `p2 = D_801DFD90` right before its + first use, so p2's quantity is born late: local-alloc `qty_compare_1` (local-alloc.c:1598) ranks p2 (3 refs, short + life) ABOVE p1 (4 refs over 22 numbers, 3636) -> p2 takes v1 first; p1 then finds v0 (temps), v1 (p2), a0 (the + `D_801904C6` arg load precedes p1's death) busy and takes a1 — the target's assignment. sched2 then hoists both loads + above the prologue (no memory or register edge left), exactly the target's first four instructions. +- The same independence lets the `D_801DFD90` reload after call 1 and the `D_801DFD8C` reload after call 2 schedule + above the `x4C`/`x40` stores (the target's order; the free body only got it by writing the loads first). +- The `D_801904C6`/`D_801904CE` argument loads must STAY behind the object stores (target: after `sw 68(s0)` / after + `sw 76(s0)`): with struct-varying stores that needs the loads to be struct too -> the array-typed alias. Without the + aliases (n5) the arg load floats to just after `move s0,a0` (sched2) and the score is 21; one alias alone 10-11. + +## (c) The moves (all needed; single steps score worse) +1. object stores/loads through a struct type: `((OB *)param_1)->x48 = ...` (MEM_IN_STRUCT varying). +2. the two pointer globals read directly (`((SV *)D_801DFD90)->vy`) instead of via the `t`/`psVar5` temps, and `SV` + field access for the pointed-to vectors (readability; `p1[0]`/`p1[2]` score the same — n4 = 0 too). +3. `D_801904C6`/`D_801904CE` read as elements of an array-typed declaration (struct-FIXED), keeping them behind the stores. +4. `+=` with the `(s16)` cast inline instead of `sVar4`/`acc` temps (the barrier's job — acc before the t load — falls + out of the dependence graph once the loads are free). + +## (d) Generator proposal +When a register/ORDER residual involves loads of GLOBALS that the target hoists above stores through a parameter +pointer (or leaves behind them), rewrite each access's MEM_IN_STRUCT class to match: object fields through a struct +cast (`((T *)p)->f`), global scalars as plain names (non-struct fixed), and globals the target keeps ordered after the +stores as array elements (`extern T G_a[] __asm__("G")`, struct fixed) — enumerate the 2^k struct/non-struct choices +per access group, it is a small search that no current generator (R2-R41) spans. + +## (e) Tried and failed (bytes) +- n1 (inline temps, all `*(s32 *)(p+K)` casts) 28; n2 (struct `OB *o = (OB *)param_1;` local + SV) 28 — the arg loads + float to the top; n3 (struct only on x4C) 48; n10 (n11 with `OB *o` as a local) 9 — the separate local costs a + copy; n12 (`(*(s16 (*)[1])&D_801904C6)[0]`, no alias) 21 — the ARRAY_REF of a cast ADDR_EXPR is not marked; + n6 (`(&D_801904C6)[0]`) 21 — fold removes `+ 0`. +- The s104_all regen best was 7 (a marked do-while around one store) and history's best 2 (do-while + inline t). + +## (f) Where the method fell short +Step 12-16 name the aggregate channel only for ONE lever class (a table load hoisted over a store). Here it closed a +pin AND a barrier: the register residual was a sched1 ORDER consequence (births/deaths feeding qty_compare), and +the order was set by memory dependence edges. The allocation table (and localalloc_sim) explained the v1/a0 choice +but could not suggest the fix; reading the sched1 ready-list trace for WHY `lw D_801DFD90` only became ready after +the first store (an anti-dependence edge) was the step that found it. + +## (g) Structs — YES, this is the structs channel, proven on bytes +`param_1` is an object with s32 fields at 0x3C/0x40/0x44/0x48/0x4C/0x50; `D_801DFD8C`/`D_801DFD90` are `SVECTOR *` +(set in func_80180F08 to `&D_801904D4[0]` / `[2]` of an s32 array = 8-byte SVECTORs); `D_801904C6`/`D_801904CE` are +s16 members of an aggregate (8 bytes apart — plausibly the `pad` of two SVECTORs at D_801904C0/C8, or two fields of one +struct). Giving these their struct types is exactly what moves the sched.c dependence decision; with file-scope types +the two aliases disappear. diff --git a/.run/P36/agents/ov_SC06_029__func_80184EFC/body.c b/.run/P36/agents/ov_SC06_029__func_80184EFC/body.c new file mode 100644 index 000000000..d56bea07f --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80184EFC/body.c @@ -0,0 +1,34 @@ +void func_80184EFC(s32 a0) { + extern s32 D_80190A08; + extern u16 D_80190810[]; + s32 ret; + s32 p20; + + ret = func_8012C1B8(); + *(s32 *)(a0 + 0x20) = ret; + if (ret == 0) { + func_8012CAE4((void *)a0); + return; + } + + func_8001C214(ret, 0); + + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10; + /* P36 S104 e22: the tag is ONE expression (each `|` a fresh single-set pseudo, so sched1's birthing boost, + * sched.c:2469-2544, keeps the chain after the flags store) and the flags update is a plain `|=` — the old + * shared `tmp` (a two-death pseudo, refused by local-alloc.c:472) needed a $2 pin; the `s0 = a0` copy needed $16. */ + *(s32 *)(a0 + 0x58) = (s32)&D_80190A08 | 0x10000000 | 0x20000000 | 0x40000000; + if (*(s16 *)(a0 + 0x70) & 0x8000) { + *(s16 *)(a0 + 0x34) = 1; + } + + p20 = *(s32 *)(*(s32 *)(a0 + 0x64) + 0x20); + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) = + *(u16 *)(p20 + 0x12) + D_80190810[(*(u16 *)(a0 + 0x70) & 0xF) * 6] + 0xE00; + func_8012B2CC(a0); + + func_8012B178(a0, (s32)0xFFFC0000); + + *(s32 *)(a0 + 0x1C) = 0x20; + *(u16 *)(a0 + 0x2) += 1; +} diff --git a/.run/P36/agents/ov_SC06_029__func_80184EFC/mechanism.md b/.run/P36/agents/ov_SC06_029__func_80184EFC/mechanism.md new file mode 100644 index 000000000..950b8268e --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80184EFC/mechanism.md @@ -0,0 +1,58 @@ +# func_80184EFC (ov_SC06_029) — agent e22, P36 S104 + +**Result: score 0, ZERO levers (both pins, $16 and $2, gone). Levers 2 -> 0.** Plain C: no asm, no volatile, no alias, +no signature change. + +## (a) The residual +Lever-free: score 35 (COUNT, 66 vs 63): an extra callee-saved register (`move s1,s0`, 32-byte frame) and a +v0/v1/a0 rotation through the flags/tag block (`sub` v0 vs v1, flags temp a0 vs v0, tag accumulator a0 vs v0, +0x40000000 v1 vs a0, the `lh 112` test v0 vs v1). + +## (b) The passes and decisions +1. `s32 s0; s0 = a0;` — the parameter pseudo and its copy survive as TWO callee-saved pseudos (the copy is live past + calls on two paths); deleting the copy and using `a0` (step 15 d24) removes the `$16` pin's job: 35 -> 16 alone. +2. `tmp` reused for the flags update AND the tag accumulator dies twice (at the `sh 44` and at the `sw 88`), so + local-alloc refuses it (`reg_n_deaths == 1`, local-alloc.c:472) and global-alloc sees v0 already taken by the + locals `sub` and the `lh 112` test value -> tmp lands in a0 (localalloc_sim: `sub` q0 -> v0, r83 -> v1, 0 mismatches). + The target's assignment (tag in v0 first, `sub` v1, 0x40000000 a0, test value v1) is what local-alloc gives when + the tag is a LOCAL quantity of high priority. +3. Splitting the temp naively (one `tag` variable, `tag |= C` three times) makes tag single-death but lets sched1 hoist + the whole tag chain above the flags load/store (21): the chain's insns have priority 1 (`priority()` sched.c:1425, + latency-1 chain), the flags store priority 3, and a 4-set `tag` gets no birthing boost (`birthing_insn_p` + sched.c:2469 needs `reg_n_sets == 1`), so the backward scheduler picks the store first = places it last. +4. Written as ONE expression, `(s32)&D_80190A08 | 0x10000000 | 0x20000000 | 0x40000000` (fold cannot associate the + constants onto a SYMBOL address, so the three `or`s survive), every step is a fresh single-set pseudo: each gets + the birthing boost (adjust_priority, sched.c:2507-2544) the moment its consumer is scheduled, so the chain is placed + right before the `sw 88` — after the flags store — and the tag quantity is local, ranks first, takes v0. + Proven on bytes: a2 (one 4-set tag var) 21 vs a6 (four single-set vars g1..g4) 0 vs a8 (one expression) 0. + +## (c) The moves +1. delete `s0 = a0`, use the parameter (`$16` pin gone). +2. flags update as `*(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10;` (no shared temp). +3. tag as one expression `(s32)&D_80190A08 | 0x10000000 | 0x20000000 | 0x40000000` (the `$2` pin gone). + (cosmetic, all 0: the cast on func_8012C1B8 dropped — the TU's prototype already returns s32; the `val`/`sub2`/`nib` + temps folded into one statement with `D_80190810[nib * 6]`; `+= 1` on the u16 counter.) + Six other lever-free TUs spell the same tag the same way (e.g. ov_SC06_022 `(s32)&D_80190F8C | 0x10000000 | + 0x40000000`, ov_SC02_011:686), which corroborates the idiom. + +## (d) Generator proposal +When a register residual sits on a temp that is assigned a chain `t = X; t = t | C1; t = t | C2; ...; *M = t;` +(or a temp reused for two unrelated chains), rewrite the chain as ONE expression stored directly (`*M = X | C1 | C2`) +and any read-modify-write through the temp as `*P |= K;` — the single-set pseudos restore sched1's birthing boost and +local-alloc eligibility at once. + +## (e) Tried and failed (bytes) +- a1 (only the `s0` copy removed) 16; a2/a3/a4 (shared temp split into flags var + ONE 4-set tag var) 21 — the + chain hoists above the flags store (the tree header's warning, confirmed, and why the old author kept one shared + pseudo plus a $2 pin); a5 (flags temp as u16 `nib`) 12. +- s104_all regen best 11 (R10 param-alias + R6 inline tmp): the generators inline one `tmp` step at a time and never + produce the whole chain as one expression. + +## (f) Where the method fell short +Nothing in steps 12-16 names "a multi-set temp kills the birthing boost" as a SCHEDULING fact (step 12's d8 covers +width, the 80185D44 header covers a 2-set s16); the `.sched` ready list (`(3)` vs `(7f000001)`) made it visible. + +## (g) Structs +Not needed here and would not change the closing decision (register-only chain; the flags/tag stores are to +different objects). An object struct for `a0` (0x1C/0x20/0x2C/0x34/0x58/0x64/0x70) would read better but is +cosmetic; untested on bytes. diff --git a/.run/P36/agents/ov_SC06_029__func_80185D44/body.c b/.run/P36/agents/ov_SC06_029__func_80185D44/body.c new file mode 100644 index 000000000..1733b7d3c --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80185D44/body.c @@ -0,0 +1,33 @@ +void func_80185D44(void *a0) { + s32 v0; + s32 v1; + s32 m; + s16 t; + u8 *p; + + v0 = func_8012C1B8(); + *(s32 *)((s32)a0 + 0x20) = v0; + if (v0 == 0) { + func_8012CAE4(a0); + return; + } + func_8001C214(v0, (s32)D_801A0734); + m = 0x7FFF0000; + __asm__("" : "=r"(m) : "0"(m)); // !FAKE: launder m — cse.c fold_rtx folds `m |= 0xFFFF` to one large_int movsi whose sched1 split halves get ADJACENT luids (sched.c:4830, rank_for_schedule :2428); the target needs luid(lui) < luid(t=0x80) and luid(t=-2) < luid(ori) (P36 S104 e22 minimum-lever) + t = 0x80; + *(s16 *)((s32)a0 + 0xE0) = t; + *(s16 *)((s32)a0 + 0xDE) = t; + *(s16 *)((s32)a0 + 0xDC) = t; + t = -2; + *(s16 *)((s32)a0 + 0xE2) = t; + p = (u8 *)D_801DDBF4; + v1 = *(s32 *)((s32)a0 + 0x20); + *(u16 *)(v1 + 0x2C) |= 0x80; + v1 = *(s32 *)((s32)a0 + 0x20); + *(s32 *)(v1 + 0x80) = (s32)a0 + 0xDC; + *(s16 *)(p + 0x1A) = 0x800; + *(s16 *)(p + 0x18) = 0x800; + m |= 0xFFFF; + *(s32 *)(p + 4) &= m; + *(u16 *)((s32)a0 + 2) = *(u16 *)((s32)a0 + 2) + 1; +} diff --git a/.run/P36/agents/ov_SC06_029__func_80185D44/mechanism.md b/.run/P36/agents/ov_SC06_029__func_80185D44/mechanism.md new file mode 100644 index 000000000..36a35025b --- /dev/null +++ b/.run/P36/agents/ov_SC06_029__func_80185D44/mechanism.md @@ -0,0 +1,59 @@ +# func_80185D44 (ov_SC06_029) — agent e22, P36 S104 + +**Result: score 0 with ONE marked lever (the tree's launder, re-marked in the step-9 format). Levers 1 -> 1. +No plain-C spelling found; the lever is argued irreducible below (proven on bytes for every alternative tried).** + +## (a) The residual +Lever-free: score 2 (ORDER, 47 = 47 ins). The mask `0x7FFFFFFF` is emitted `lui a1,0x7fff` ... `ori a1,a1,0xffff`; +the target puts the `lui` FIRST in the block after `jal func_8001C214` (before `li v0,128`) and the `ori` after +`lw v1,32(s0)`; mine puts the `lui` after `li v0,-2`. Same instructions, one moved. + +## (b) The pass and the decision +- cse.c `fold_rtx`: `m = 0x7FFF0000; ... m |= 0xFFFF;` folds to ONE `(set m (const_int 0x7fffffff))` at the `|=`'s + position (mips.h:2669 `CONST_COSTS` returns 0 for every CONST_INT, so the constant always wins); the first set is dead. + Seen in the `.combine` dump: insn 92 `(set (reg/v:SI 75) (const_int 2147483647))` after the `+0x18` store. +- sched.c:4830 `try_split` splits that insn by mips.md:3208 (`large_int`) into `lui`+`ori` (uids 112/113) with + ADJACENT luids (`sched_analyze` numbers insns in order, sched.c:2170-2175). +- sched.c:2428 `rank_for_schedule` ties on `INSN_LUID` (higher luid picked first by the backward scheduler). The target's + backward pick order is ... 60, **113 (ori)**, 66, 57, 54, 51, 48, 45, **112 (lui)**: the ori must beat `t = -2` (57) and + the `lw v1` (66) on luid, the lui must lose to 45..57 on luid — i.e. luid(lui) < luid(45) < luid(57) < luid(ori), which + two adjacent luids cannot satisfy. None of these insns gets the birthing boost (`t` is set twice, the split halves + set reg 75 twice; `birthing_insn_p` sched.c:2469 needs `reg_n_sets == 1`), so priority does not break the tie either. + => the original compiled the two halves as TWO RTL insns, which needs cse to NOT know m's value at the `|=`. + +## (c) The move +None closes it in plain C. Delivered: the tree body with its one launder, marked +`// !FAKE: launder m — ... (P36 S104 e22 minimum-lever)`; `--try` = 0. + +## (d) Generator proposal +When the residual is a `lui X,hi` / `ori X,X,lo` pair whose lui sits EARLIER than the lever-free placement and the ori +stays put, the source must emit the halves as two insns: try `m = HI<<16; ; m |= LO;` with the first set placed +at the lui's block position (a generator can compute that position from the target objdump); if cse folds it (it +always has so far), the case is a launder class for the STRUCTS phase, not a search target. + +## (e) Tried and failed (bytes) +- `m = 0x7FFFFFFF;` placed before each of the 7 statement positions (scratch/gen1.py, g1/v0..v6): 4, 6, 2, 2, 2, 2, 2. + v0 (at the top) puts the lui first as the target does but drags the ori with it (adjacent luids) — the prediction. +- `do { m = 0x7FFF0000; } while (0);` (cse1 stops at NOTE_INSN_LOOP_END, cse.c:8055) -> 2: cse2 (`after_loop`) + ignores the note and folds anyway. Same with `t = 0x80` inside the do-while -> 2. +- `*(s32 *)(p + 4) &= m | 0xFFFF;` -> 2. The s104_all regen (R2-R41) best is also 2 (177 compiles), and an + EXHAUSTIVE pass of every R-family candidate on body_free (244 candidates via `tools/delever.py recipe_candidates`, + read-only import, scratch/regen.py) has best 2 too. +- m = 0x7FFFFFFF at 7 positions x the a0/p stores as struct vs non-struct accesses (scratch/gen3.py, 28 bodies): best 2 + — memory-dependence edges do not reach two halves of one split constant. +- Every cse-visible spelling of the constant (shift of a narrow const, union field insert, bitfield clear at bit 31) + reaches the same `(const_int 0x7fffffff)` by reasoning (store_fixed_bit_field's `mask_rtx` is a CONST_INT); not all + compiled. + +## (f) Where the method fell short +Nothing in steps 12-16 targets a sched1 SPLIT insn; the luid arithmetic (adjacent split halves) is the whole answer and +it needs the `.sched` ready-list trace plus the pre-sched `.combine` order, not the allocation table. +Survey: across the 4,284 baseline objects, lui/ori gaps >= 4 are common, but the ones I sampled (func_8017E590, +func_80183A70, func_801810B0, func_801439FC) are all reorg filling a branch delay slot with the lui — a different, natural +mechanism that does not apply here (no branch after the call). + +## (g) Structs +No. The lever keeps a CONSTANT opaque to cse's constant folding; giving `p`/`a0` struct types changes the addressing +of the stores (aggregate MEM flags, expr.c:4568-4577) and so possibly their dependence edges in sched, but it cannot +stop fold_rtx from folding `0x7FFF0000 | 0xFFFF`, which is what forces the single insn. The split needs the halves to +be distinct RTL, and no struct shape produces that. diff --git a/.run/P36/delever/calibration.json b/.run/P36/delever/calibration.json index 85745b12e..3a5618d24 100644 --- a/.run/P36/delever/calibration.json +++ b/.run/P36/delever/calibration.json @@ -1,7 +1,7 @@ { - "head": "aa0564d72", + "head": "8733d36da", "stamp": "15956e4a96c4", - "generated": "2026-09-11 03:27", + "generated": "2026-09-11 03:53", "aliases": [ "main", "ov_SC03_014", @@ -21,207 +21,207 @@ "main": { "objects": 85, "identical": 85, - "seconds": 10.808999999999996, - "mean_s": 0.127 + "seconds": 7.850000000000001, + "mean_s": 0.092 }, "ov_SC03_014": { "objects": 32, "identical": 32, - "seconds": 6.97, - "mean_s": 0.218 + "seconds": 5.756, + "mean_s": 0.18 }, "ov_SC03_015": { "objects": 32, "identical": 32, - "seconds": 7.423, - "mean_s": 0.232 + "seconds": 5.114, + "mean_s": 0.16 }, "ov_SC04_011": { "objects": 28, "identical": 28, - "seconds": 6.887, - "mean_s": 0.246 + "seconds": 4.3870000000000005, + "mean_s": 0.157 } }, "per_object_seconds": { - "build/src/800.o": 0.954, - "build/src/800_b.o": 0.169, - "build/src/800_b_2.o": 0.411, - "build/src/800_b_o0a.o": 0.093, - "build/src/800_c.o": 0.256, - "build/src/800b2.o": 0.146, - "build/src/apicard1.o": 0.097, - "build/src/apicard2.o": 0.12, - "build/src/apicard3.o": 0.147, - "build/src/apicard4.o": 0.101, - "build/src/apicard5.o": 0.105, - "build/src/apicard6.o": 0.143, - "build/src/apicard7.o": 0.12, - "build/src/boot.o": 0.15, + "build/src/800.o": 0.566, + "build/src/800_b.o": 0.146, + "build/src/800_b_2.o": 0.277, + "build/src/800_b_o0a.o": 0.113, + "build/src/800_c.o": 0.238, + "build/src/800b2.o": 0.135, + "build/src/apicard1.o": 0.089, + "build/src/apicard2.o": 0.107, + "build/src/apicard3.o": 0.081, + "build/src/apicard4.o": 0.12, + "build/src/apicard5.o": 0.107, + "build/src/apicard6.o": 0.102, + "build/src/apicard7.o": 0.1, + "build/src/boot.o": 0.158, "build/src/gap.o": 0.102, - "build/src/libapi1.o": 0.127, - "build/src/libapi2.o": 0.073, - "build/src/libc2_1.o": 0.087, - "build/src/libc2_2.o": 0.084, - "build/src/libcd1.o": 0.143, - "build/src/libcd2.o": 0.125, - "build/src/libetc.o": 0.116, - "build/src/libgpu.o": 0.134, - "build/src/libgpu2.o": 0.104, - "build/src/libgs1.o": 0.13, - "build/src/libgs2.o": 0.08, - "build/src/libgs3.o": 0.087, - "build/src/libgs4.o": 0.099, - "build/src/libgs5.o": 0.119, - "build/src/libgs6.o": 0.101, - "build/src/libgs7.o": 0.087, - "build/src/libgs8.o": 0.087, - "build/src/libgte1.o": 0.072, - "build/src/libgte10.o": 0.121, - "build/src/libgte11.o": 0.084, - "build/src/libgte12.o": 0.101, - "build/src/libgte13.o": 0.134, - "build/src/libgte14.o": 0.077, - "build/src/libgte15.o": 0.114, - "build/src/libgte16.o": 0.118, - "build/src/libgte17.o": 0.137, - "build/src/libgte18.o": 0.135, - "build/src/libgte19.o": 0.118, - "build/src/libgte2.o": 0.096, - "build/src/libgte20.o": 0.09, - "build/src/libgte21.o": 0.112, - "build/src/libgte22.o": 0.108, - "build/src/libgte23.o": 0.095, - "build/src/libgte24.o": 0.103, - "build/src/libgte25.o": 0.122, - "build/src/libgte26.o": 0.096, - "build/src/libgte27.o": 0.124, - "build/src/libgte28.o": 0.11, - "build/src/libgte29.o": 0.092, - "build/src/libgte3.o": 0.121, - "build/src/libgte30.o": 0.134, - "build/src/libgte4.o": 0.17, - "build/src/libgte5.o": 0.086, - "build/src/libgte6.o": 0.123, - "build/src/libgte7.o": 0.104, - "build/src/libgte8.o": 0.112, - "build/src/libgte9.o": 0.131, - "build/src/libmcrd1.o": 0.109, - "build/src/libmcrd2.o": 0.114, - "build/src/libpad1.o": 0.131, - "build/src/libpad2.o": 0.131, - "build/src/sgap.o": 0.093, - "build/src/sgap_2.o": 0.089, - "build/src/sgap_3.o": 0.123, - "build/src/sgap_4.o": 0.132, - "build/src/sgap_5.o": 0.115, - "build/src/sgap_6.o": 0.078, - "build/src/sgap_8.o": 0.107, - "build/src/snd1.o": 0.104, - "build/src/snd10.o": 0.095, - "build/src/snd11.o": 0.121, - "build/src/snd12.o": 0.097, - "build/src/snd2.o": 0.128, - "build/src/snd3.o": 0.094, - "build/src/snd4.o": 0.167, - "build/src/snd5.o": 0.104, - "build/src/snd6.o": 0.171, - "build/src/snd7.o": 0.093, - "build/src/snd8.o": 0.072, - "build/src/snd9.o": 0.104, - "build/src/ov_SC03_014/ov_SC03_014.o": 0.209, - "build/src/ov_SC03_014/ov_SC03_014_after.o": 0.722, - "build/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.o": 0.574, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135888.o": 0.099, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135A4C.o": 0.136, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135D20.o": 0.15, - "build/src/ov_SC03_014/ov_SC03_014_jr_801380E0.o": 0.283, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013C98C.o": 0.19, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013F350.o": 0.109, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013FFD8.o": 0.138, - "build/src/ov_SC03_014/ov_SC03_014_jr_80140608.o": 0.253, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015444C.o": 0.098, - "build/src/ov_SC03_014/ov_SC03_014_jr_80154C24.o": 0.222, - "build/src/ov_SC03_014/ov_SC03_014_jr_801588CC.o": 0.132, - "build/src/ov_SC03_014/ov_SC03_014_jr_80159C84.o": 0.101, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015A3C8.o": 0.11, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015AE2C.o": 0.117, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015C32C.o": 0.678, - "build/src/ov_SC03_014/ov_SC03_014_jr_8016AB6C.o": 0.387, - "build/src/ov_SC03_014/ov_SC03_014_jr_80171B4C.o": 0.135, - "build/src/ov_SC03_014/ov_SC03_014_jr_801734BC.o": 0.268, - "build/src/ov_SC03_014/ov_SC03_014_jr_801789AC.o": 0.124, - "build/src/ov_SC03_014/ov_SC03_014_jr_80178D40.o": 0.142, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017A4AC.o": 0.118, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.o": 0.256, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.o": 0.276, - "build/src/ov_SC03_014/ov_SC03_014_jr_80184440.o": 0.087, - "build/src/ov_SC03_014/ov_SC03_014_jr_801848E4.o": 0.408, - "build/src/ov_SC03_014/ov_SC03_014_o0b.o": 0.074, - "build/src/ov_SC03_014/ov_SC03_014_o0c.o": 0.125, - "build/src/ov_SC03_014/ov_SC03_014_o0d.o": 0.114, - "build/src/ov_SC03_014/ov_SC03_014_o0e.o": 0.135, - "build/src/ov_SC03_015/ov_SC03_015.o": 0.244, - "build/src/ov_SC03_015/ov_SC03_015_after.o": 0.731, - "build/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.o": 0.593, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135888.o": 0.081, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135A4C.o": 0.078, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135D20.o": 0.182, - "build/src/ov_SC03_015/ov_SC03_015_jr_801380E0.o": 0.232, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013C98C.o": 0.173, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013F350.o": 0.113, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013FFD8.o": 0.121, - "build/src/ov_SC03_015/ov_SC03_015_jr_80140608.o": 0.294, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015444C.o": 0.149, - "build/src/ov_SC03_015/ov_SC03_015_jr_80154C24.o": 0.291, - "build/src/ov_SC03_015/ov_SC03_015_jr_801588CC.o": 0.141, - "build/src/ov_SC03_015/ov_SC03_015_jr_80159C84.o": 0.121, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015A3C8.o": 0.111, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015AE2C.o": 0.169, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015C32C.o": 0.746, - "build/src/ov_SC03_015/ov_SC03_015_jr_8016AB6C.o": 0.429, - "build/src/ov_SC03_015/ov_SC03_015_jr_80171B4C.o": 0.177, - "build/src/ov_SC03_015/ov_SC03_015_jr_801734BC.o": 0.315, - "build/src/ov_SC03_015/ov_SC03_015_jr_801789AC.o": 0.121, - "build/src/ov_SC03_015/ov_SC03_015_jr_80178D40.o": 0.163, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017A4AC.o": 0.154, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.o": 0.291, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.o": 0.278, - "build/src/ov_SC03_015/ov_SC03_015_jr_80184440.o": 0.118, - "build/src/ov_SC03_015/ov_SC03_015_jr_801848E4.o": 0.404, - "build/src/ov_SC03_015/ov_SC03_015_o0b.o": 0.092, - "build/src/ov_SC03_015/ov_SC03_015_o0c.o": 0.095, - "build/src/ov_SC03_015/ov_SC03_015_o0d.o": 0.084, - "build/src/ov_SC03_015/ov_SC03_015_o0e.o": 0.132, - "build/src/ov_SC04_011/ov_SC04_011.o": 0.196, - "build/src/ov_SC04_011/ov_SC04_011_after.o": 0.695, - "build/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.o": 0.597, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135888.o": 0.118, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135A4C.o": 0.108, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135D20.o": 0.206, - "build/src/ov_SC04_011/ov_SC04_011_jr_801380E0.o": 0.274, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013C98C.o": 0.193, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013F350.o": 0.163, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013FFD8.o": 0.115, - "build/src/ov_SC04_011/ov_SC04_011_jr_80140608.o": 0.279, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015444C.o": 0.15, - "build/src/ov_SC04_011/ov_SC04_011_jr_80154C24.o": 0.288, - "build/src/ov_SC04_011/ov_SC04_011_jr_801588CC.o": 0.192, - "build/src/ov_SC04_011/ov_SC04_011_jr_80159C84.o": 0.118, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015A3C8.o": 0.122, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015AE2C.o": 0.156, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015C32C.o": 0.563, - "build/src/ov_SC04_011/ov_SC04_011_jr_8016AB6C.o": 0.408, - "build/src/ov_SC04_011/ov_SC04_011_jr_80171B4C.o": 0.176, - "build/src/ov_SC04_011/ov_SC04_011_jr_801734BC.o": 0.275, - "build/src/ov_SC04_011/ov_SC04_011_jr_801789AC.o": 0.111, - "build/src/ov_SC04_011/ov_SC04_011_jr_80178D40.o": 0.179, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017A4AC.o": 0.124, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.o": 0.176, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017D494.o": 0.689, - "build/src/ov_SC04_011/ov_SC04_011_o0b.o": 0.1, - "build/src/ov_SC04_011/ov_SC04_011_o0c.o": 0.116 + "build/src/libapi1.o": 0.1, + "build/src/libapi2.o": 0.066, + "build/src/libc2_1.o": 0.083, + "build/src/libc2_2.o": 0.081, + "build/src/libcd1.o": 0.069, + "build/src/libcd2.o": 0.066, + "build/src/libetc.o": 0.065, + "build/src/libgpu.o": 0.073, + "build/src/libgpu2.o": 0.081, + "build/src/libgs1.o": 0.066, + "build/src/libgs2.o": 0.057, + "build/src/libgs3.o": 0.038, + "build/src/libgs4.o": 0.04, + "build/src/libgs5.o": 0.037, + "build/src/libgs6.o": 0.043, + "build/src/libgs7.o": 0.049, + "build/src/libgs8.o": 0.044, + "build/src/libgte1.o": 0.044, + "build/src/libgte10.o": 0.047, + "build/src/libgte11.o": 0.05, + "build/src/libgte12.o": 0.049, + "build/src/libgte13.o": 0.047, + "build/src/libgte14.o": 0.053, + "build/src/libgte15.o": 0.127, + "build/src/libgte16.o": 0.123, + "build/src/libgte17.o": 0.139, + "build/src/libgte18.o": 0.113, + "build/src/libgte19.o": 0.094, + "build/src/libgte2.o": 0.085, + "build/src/libgte20.o": 0.125, + "build/src/libgte21.o": 0.135, + "build/src/libgte22.o": 0.138, + "build/src/libgte23.o": 0.081, + "build/src/libgte24.o": 0.1, + "build/src/libgte25.o": 0.112, + "build/src/libgte26.o": 0.095, + "build/src/libgte27.o": 0.12, + "build/src/libgte28.o": 0.118, + "build/src/libgte29.o": 0.152, + "build/src/libgte3.o": 0.076, + "build/src/libgte30.o": 0.082, + "build/src/libgte4.o": 0.08, + "build/src/libgte5.o": 0.065, + "build/src/libgte6.o": 0.064, + "build/src/libgte7.o": 0.065, + "build/src/libgte8.o": 0.072, + "build/src/libgte9.o": 0.057, + "build/src/libmcrd1.o": 0.067, + "build/src/libmcrd2.o": 0.059, + "build/src/libpad1.o": 0.053, + "build/src/libpad2.o": 0.055, + "build/src/sgap.o": 0.045, + "build/src/sgap_2.o": 0.048, + "build/src/sgap_3.o": 0.048, + "build/src/sgap_4.o": 0.047, + "build/src/sgap_5.o": 0.049, + "build/src/sgap_6.o": 0.041, + "build/src/sgap_8.o": 0.042, + "build/src/snd1.o": 0.042, + "build/src/snd10.o": 0.042, + "build/src/snd11.o": 0.039, + "build/src/snd12.o": 0.107, + "build/src/snd2.o": 0.104, + "build/src/snd3.o": 0.092, + "build/src/snd4.o": 0.127, + "build/src/snd5.o": 0.118, + "build/src/snd6.o": 0.085, + "build/src/snd7.o": 0.13, + "build/src/snd8.o": 0.125, + "build/src/snd9.o": 0.078, + "build/src/ov_SC03_014/ov_SC03_014.o": 0.196, + "build/src/ov_SC03_014/ov_SC03_014_after.o": 0.426, + "build/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.o": 0.365, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135888.o": 0.111, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135A4C.o": 0.114, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135D20.o": 0.182, + "build/src/ov_SC03_014/ov_SC03_014_jr_801380E0.o": 0.226, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013C98C.o": 0.134, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013F350.o": 0.091, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013FFD8.o": 0.08, + "build/src/ov_SC03_014/ov_SC03_014_jr_80140608.o": 0.161, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015444C.o": 0.091, + "build/src/ov_SC03_014/ov_SC03_014_jr_80154C24.o": 0.149, + "build/src/ov_SC03_014/ov_SC03_014_jr_801588CC.o": 0.091, + "build/src/ov_SC03_014/ov_SC03_014_jr_80159C84.o": 0.075, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015A3C8.o": 0.063, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015AE2C.o": 0.061, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015C32C.o": 0.756, + "build/src/ov_SC03_014/ov_SC03_014_jr_8016AB6C.o": 0.166, + "build/src/ov_SC03_014/ov_SC03_014_jr_80171B4C.o": 0.064, + "build/src/ov_SC03_014/ov_SC03_014_jr_801734BC.o": 0.296, + "build/src/ov_SC03_014/ov_SC03_014_jr_801789AC.o": 0.115, + "build/src/ov_SC03_014/ov_SC03_014_jr_80178D40.o": 0.136, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017A4AC.o": 0.121, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.o": 0.217, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.o": 0.286, + "build/src/ov_SC03_014/ov_SC03_014_jr_80184440.o": 0.122, + "build/src/ov_SC03_014/ov_SC03_014_jr_801848E4.o": 0.316, + "build/src/ov_SC03_014/ov_SC03_014_o0b.o": 0.156, + "build/src/ov_SC03_014/ov_SC03_014_o0c.o": 0.104, + "build/src/ov_SC03_014/ov_SC03_014_o0d.o": 0.152, + "build/src/ov_SC03_014/ov_SC03_014_o0e.o": 0.133, + "build/src/ov_SC03_015/ov_SC03_015.o": 0.2, + "build/src/ov_SC03_015/ov_SC03_015_after.o": 0.311, + "build/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.o": 0.398, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135888.o": 0.106, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135A4C.o": 0.091, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135D20.o": 0.123, + "build/src/ov_SC03_015/ov_SC03_015_jr_801380E0.o": 0.152, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013C98C.o": 0.117, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013F350.o": 0.098, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013FFD8.o": 0.079, + "build/src/ov_SC03_015/ov_SC03_015_jr_80140608.o": 0.173, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015444C.o": 0.073, + "build/src/ov_SC03_015/ov_SC03_015_jr_80154C24.o": 0.16, + "build/src/ov_SC03_015/ov_SC03_015_jr_801588CC.o": 0.061, + "build/src/ov_SC03_015/ov_SC03_015_jr_80159C84.o": 0.052, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015A3C8.o": 0.044, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015AE2C.o": 0.061, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015C32C.o": 0.288, + "build/src/ov_SC03_015/ov_SC03_015_jr_8016AB6C.o": 0.283, + "build/src/ov_SC03_015/ov_SC03_015_jr_80171B4C.o": 0.167, + "build/src/ov_SC03_015/ov_SC03_015_jr_801734BC.o": 0.242, + "build/src/ov_SC03_015/ov_SC03_015_jr_801789AC.o": 0.119, + "build/src/ov_SC03_015/ov_SC03_015_jr_80178D40.o": 0.178, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017A4AC.o": 0.15, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.o": 0.216, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.o": 0.255, + "build/src/ov_SC03_015/ov_SC03_015_jr_80184440.o": 0.123, + "build/src/ov_SC03_015/ov_SC03_015_jr_801848E4.o": 0.271, + "build/src/ov_SC03_015/ov_SC03_015_o0b.o": 0.14, + "build/src/ov_SC03_015/ov_SC03_015_o0c.o": 0.13, + "build/src/ov_SC03_015/ov_SC03_015_o0d.o": 0.117, + "build/src/ov_SC03_015/ov_SC03_015_o0e.o": 0.136, + "build/src/ov_SC04_011/ov_SC04_011.o": 0.173, + "build/src/ov_SC04_011/ov_SC04_011_after.o": 0.413, + "build/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.o": 0.3, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135888.o": 0.064, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135A4C.o": 0.053, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135D20.o": 0.104, + "build/src/ov_SC04_011/ov_SC04_011_jr_801380E0.o": 0.097, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013C98C.o": 0.072, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013F350.o": 0.048, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013FFD8.o": 0.038, + "build/src/ov_SC04_011/ov_SC04_011_jr_80140608.o": 0.109, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015444C.o": 0.044, + "build/src/ov_SC04_011/ov_SC04_011_jr_80154C24.o": 0.103, + "build/src/ov_SC04_011/ov_SC04_011_jr_801588CC.o": 0.055, + "build/src/ov_SC04_011/ov_SC04_011_jr_80159C84.o": 0.101, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015A3C8.o": 0.125, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015AE2C.o": 0.134, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015C32C.o": 0.419, + "build/src/ov_SC04_011/ov_SC04_011_jr_8016AB6C.o": 0.266, + "build/src/ov_SC04_011/ov_SC04_011_jr_80171B4C.o": 0.133, + "build/src/ov_SC04_011/ov_SC04_011_jr_801734BC.o": 0.211, + "build/src/ov_SC04_011/ov_SC04_011_jr_801789AC.o": 0.129, + "build/src/ov_SC04_011/ov_SC04_011_jr_80178D40.o": 0.151, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017A4AC.o": 0.12, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.o": 0.158, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017D494.o": 0.492, + "build/src/ov_SC04_011/ov_SC04_011_o0b.o": 0.131, + "build/src/ov_SC04_011/ov_SC04_011_o0c.o": 0.144 }, "ok": true, - "seconds": 3.4 + "seconds": 18.4 } diff --git a/.run/P36/delever/ledger.jsonl b/.run/P36/delever/ledger.jsonl index 9a2cee6b7..05321e0a9 100644 --- a/.run/P36/delever/ledger.jsonl +++ b/.run/P36/delever/ledger.jsonl @@ -29491,3 +29491,4 @@ {"ts": "2026-09-11 03:27:06", "label": "s104_e25", "rung": "E", "calib": {"head": "70d1ad882", "stamp": "15956e4a96c4"}, "tu": "src/800.c", "fn": "func_80013B64", "addr": 2147564388, "aliases": null, "header": false, "includers": 0, "nhash_before": "fbfac9cee5fb64c9fa319a52949fd68de801f984", "nhash_after": "708d68cde5f3921f8822a0c90bd4b8c3c29b74fe", "source": ".run/P36/agents/main__func_80013B64/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.659, "objects": ["build/src/800.o"], "before_text": "void func_80013B64(s32 param_1, s32 param_2, s32 param_3)\n{\n s16 ident[16];\n s16 rot[16];\n s32 sin_val;\n s32 cos_val;\n s32 v1;\n register s16 *v0p __asm__(\"$2\"); // !FAKE: pin $2 \u2014 NEEDED DIFFERS (P36 rung B tus9)\n s16 *m0p;\n\n func_80013F3C(ident);\n sin_val = func_8004787C((s16)param_1);\n cos_val = func_80047948((s16)param_1);\n\n v1 = -sin_val;\n __asm__ __volatile__(\"\"); // !FAKE: barrier \u2014 NEEDED DIFFERS (P36 rung B tus9)\n rot[0] = (s16)cos_val;\n rot[4] = (s16)cos_val;\n rot[8] = 0x1000;\n __asm__ __volatile__(\"\"); // !FAKE: barrier \u2014 NEEDED DIFFERS (P36 rung B tus9)\n v0p = rot;\n rot[3] = (s16)sin_val;\n m0p = ident;\n rot[1] = (s16)v1;\n rot[2] = 0;\n rot[5] = 0;\n rot[6] = 0;\n rot[7] = 0;\n\n __asm__ __volatile__ (\n \"lw $12, 0(%1);\"\n \"lw $13, 4(%1);\"\n \"ctc2 $12, $0;\"\n \"ctc2 $13, $1;\"\n \"lw $12, 8(%1);\"\n \"lw $13, 12(%1);\"\n \"lw $14, 16(%1);\"\n \"ctc2 $12, $2;\"\n \"ctc2 $13, $3;\"\n \"ctc2 $14, $4;\"\n \"lhu $12, 0(%0);\"\n \"lhu $13, 6(%0);\"\n \"lhu $14, 12(%0);\"\n \"mtc2 $12, $9;\"\n \"mtc2 $13, $10;\"\n \"mtc2 $14, $11;\"\n \"nop;\"\n \"nop;\"\n \"mvmva 1, 0, 3, 3, 0;\"\n \"mfc2 $12, $9;\"\n \"mfc2 $13, $10;\"\n \"mfc2 $14, $11;\"\n \"sh $12, 0(%1);\"\n \"sh $13, 6(%1);\"\n \"sh $14, 12(%1);\"\n \"addiu $2, $sp, 50;\"\n \"lhu $12, 0($2);\"\n \"lhu $13, 6($2);\"\n \"lhu $14, 12($2);\"\n \"mtc2 $12, $9;\"\n \"mtc2 $13, $10;\"\n \"mtc2 $14, $11;\"\n \"nop;\"\n \"nop;\"\n \"mvmva 1, 0, 3, 3, 0;\"\n \"addiu $2, $sp, 18;\"\n \"mfc2 $12, $9;\"\n \"mfc2 $13, $10;\"\n \"mfc2 $14, $11;\"\n \"sh $12, 0($2);\"\n \"sh $13, 6($2);\"\n \"sh $14, 12($2);\"\n \"addiu $2, $sp, 52;\"\n \"lhu $12, 0($2);\"\n \"lhu $13, 6($2);\"\n \"lhu $14, 12($2);\"\n \"mtc2 $12, $9;\"\n \"mtc2 $13, $10;\"\n \"mtc2 $14, $11;\"\n \"nop;\"\n \"nop;\"\n \"mvmva 1, 0, 3, 3, 0;\"\n \"addiu $2, $sp, 20;\"\n \"mfc2 $12, $9;\"\n \"mfc2 $13, $10;\"\n \"mfc2 $14, $11;\"\n \"sh $12, 0($2);\"\n \"sh $13, 6($2);\"\n \"sh $14, 12($2)\"\n :\n : \"r\"(v0p), \"r\"(m0p)\n : \"$12\", \"$13\", \"$14\", \"$2\"\n );\n\n func_8001282C(m0p);\n func_800484EC(m0p, param_2, param_3);\n}\n", "after_text": "void func_80013B64(s32 param_1, s32 param_2, s32 param_3)\n{\n s16 matrix[16];\n s16 rot[16];\n s32 sin_val;\n s32 cos_val;\n u16 v1;\n s16 *rotp;\n s16 *matp;\n\n func_80013F3C(matrix);\n sin_val = func_8004787C((s16)param_1);\n cos_val = func_80047948((s16)param_1);\n\n v1 = -sin_val;\n rot[0] = cos_val;\n rot[4] = cos_val;\n rot[8] = 0x1000;\n rotp = rot;\n rot[3] = sin_val;\n matp = matrix;\n rot[1] = v1;\n rot[2] = 0;\n rot[5] = 0;\n rot[6] = 0;\n rot[7] = 0;\n\n gte_SetRotMatrix(matp);\n gte_ldclmv(rotp);\n gte_rtir();\n gte_stclmv(matp);\n gte_ldclmv(rotp + 1);\n gte_rtir();\n gte_stclmv(matp + 1);\n gte_ldclmv(rotp + 2);\n gte_rtir();\n gte_stclmv(matp + 2);\n\n func_8001282C(matp);\n func_800484EC(matp, param_2, param_3);\n}\n"} {"ts": "2026-09-11 03:27:35", "label": "s104_e25", "rung": "E", "calib": {"head": "811684515", "stamp": "15956e4a96c4"}, "tu": "src/800.c", "fn": "func_800279AC", "addr": 2147645868, "aliases": null, "header": false, "includers": 0, "nhash_before": "0ba73216abf13ed651635af0316f4989b7492c1b", "nhash_after": "b5ed8ab0eaa553a1be780956e8f89e427af569e5", "source": ".run/P36/agents/main__func_800279AC/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.503, "objects": ["build/src/800.o"], "before_text": "LineG4 *func_800279AC(SrcQ *src, Vtx8 *vb, s32 unused, LineG4 *prim, s32 n, s32 shift, u32 *ot)\n{\n s32 flag;\n s32 otz;\n\n /* cookbook \u00a721 zero-byte re-tie: without it loop.c's record_initial takes the biv's\n * initial value straight from the parameter COPY (set prim (reg $a3)), so the +4 giv is\n * emitted as (plus (reg $a3) 4) -- $a3 then stays live past the copy, conflicts with the\n * prim pseudo, and prim/giv land in $t1/$a3 (target: $a3/$t1). The re-tie makes the\n * pre-loop set non-invariant so the giv is derived from the PSEUDO and prim coalesces\n * into $a3. Emits nothing. */\n __asm__ (\"\" : \"=r\"(prim) : \"0\"(prim)); // !FAKE: launder \u2014 NEEDED DIFFERS (P36 rung B tus9)\n for (; n != 0; n--, src++) {\n gte_ldv3(&vb[src->i0], &vb[src->i1], &vb[src->i2]);\n gte_rtpt();\n prim->rgb1 = src->rgb1;\n prim->rgb2 = src->rgb2;\n prim->rgb3 = src->rgb3;\n gte_stflg(&flag);\n if (flag & 0xFFFFEFFF) {\n continue;\n }\n gte_nclip();\n gte_stopz(&otz);\n if (otz <= 0) {\n continue;\n }\n gte_stsxy3_ft3(prim);\n gte_ldv0(&vb[src->i3]);\n gte_rtps();\n gte_stflg(&flag);\n if (flag & 0xFFFFEFFF) {\n continue;\n }\n gte_stsxy(&prim->xy3);\n prim->term = src->term;\n /* \u00a75a zero-byte barrier: else sched2 hoists the D_80078D88 load above this store and\n * eats the two load-delay nops the target keeps (the -2 length drift). */\n if (D_80078D88[0] & 0x8000) {\n s32 sz[4];\n s32 m, k;\n gte_stsz4(&sz[0], &sz[1], &sz[2], &sz[3]);\n m = sz[2];\n if (m < sz[3]) {\n m = sz[3];\n }\n k = sz[0];\n if (k < sz[1]) {\n k = sz[1];\n }\n if (k < m) {\n k = m;\n }\n otz = k >> 2;\n } else {\n gte_avsz4();\n gte_stotz(&otz);\n }\n prim->rgb0 = (src->rgb0 & 0xFFFFFF) | ((u32)src->code << 24);\n /* \u00a75a zero-byte barrier: keeps the rgb0 store ahead of the OT-link block instead of\n * letting sched2 interleave the `otz` reload into the rgb0 chain. */\n __asm__ __volatile__ (\"\" : : : \"memory\"); // !FAKE: barrier memory \u2014 NEEDED DIFFERS (P36 rung B tus9)\n {\n u32 *p = &ot[otz >> shift];\n prim->tag = (*p & 0xFFFFFF) | 0x09000000;\n *p = (u32)prim & 0xFFFFFF;\n }\n prim++;\n }\n return prim;\n}\n", "after_text": "LineG4 *func_800279AC(SrcQ *src, Vtx8 *vb, s32 unused, LineG4 *prim, s32 n, s32 shift, u32 *ot)\n{\n struct { s32 flag, otz, sz0, sz1, sz2, sz3; } g;\n LineG4 *p = prim;\n s32 m, k;\n\n for (; n != 0; n--, src++) {\n gte_ldv3(&vb[src->i0], &vb[src->i1], &vb[src->i2]);\n gte_rtpt();\n p->rgb1 = src->rgb1;\n p->rgb2 = src->rgb2;\n p->rgb3 = src->rgb3;\n gte_stflg(&g.flag);\n if (g.flag & 0xFFFFEFFF) {\n continue;\n }\n gte_nclip();\n gte_stopz(&g.otz);\n if (g.otz <= 0) {\n continue;\n }\n gte_stsxy3_ft3(p);\n gte_ldv0(&vb[src->i3]);\n gte_rtps();\n gte_stflg(&g.flag);\n if (g.flag & 0xFFFFEFFF) {\n continue;\n }\n gte_stsxy(&p->xy3);\n p->term = src->term;\n if (D_80078D88[0] & 0x8000) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n m = g.sz2;\n if (m < g.sz3) {\n m = g.sz3;\n }\n k = g.sz0;\n if (k < g.sz1) {\n k = g.sz1;\n }\n if (k < m) {\n k = m;\n }\n g.otz = k >> 2;\n } else {\n gte_avsz4();\n gte_stotz(&g.otz);\n }\n p->rgb0 = (src->rgb0 & 0xFFFFFF) | ((u32)src->code << 24);\n {\n u32 *q = &ot[g.otz >> shift];\n p->tag = (*q & 0xFFFFFF) | 0x09000000;\n *q = (u32)p & 0xFFFFFF;\n }\n p++;\n }\n return p;\n}\n"} {"ts": "2026-09-11 03:28:02", "label": "s104_e25", "rung": "E", "calib": {"head": "aa0564d72", "stamp": "15956e4a96c4"}, "tu": "src/800.c", "fn": "func_800277DC", "addr": 2147645404, "aliases": null, "header": false, "includers": 0, "nhash_before": "50b306f2c73fa9f8a23341f79e47d48063531f58", "nhash_after": "42f74cc53ae1ca675eeb8b096c1212f11cbda151", "source": ".run/P36/agents/main__func_800277DC/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.487, "objects": ["build/src/800.o"], "before_text": "void *func_800277DC(void *a0, SVECTOR800277DC *a1, void *a2, u8 *a3,\n s32 count, s32 shift, s32 *ot)\n{\n /* The five GTE scratch slots MUST be ONE array, not five scalars. gcc-2.7.2 assigns a\n * stack slot at the point each addressable local's address is first taken, NOT in\n * declaration order; hoisting &otz/&sz0/&sz1 into pre-loop pointer temps (needed to put\n * their three `addiu $sp` ahead of the mask/t0/t1 setup, see below) therefore stole slot 0\n * from `flag` and shifted the whole frame. One array pins the layout:\n * st[0]=flag @sp+0 st[1]=otz @sp+4 st[2]=sz0 @sp+8 st[3]=sz1 @sp+0xC st[4]=sz2 @sp+0x10\n * &st[0] folds to plain $sp, which is why `flag` is touched as 0($sp) with no address reg. */\n s32 st[5];\n /* t0/t1 pins ARE load-bearing (unpinning them re-drifts to 124 ins): they reproduce the\n * hand-budgeted src/dst induction-variable allocation so every field offset stays a direct\n * displacement off $t0 / $t1. cnt/mask/shiftAmt/otp need no pin -- gcc lands them on\n * $t2/$t3/$t9/$t8 on its own, and pinning `otp` to $24 actively BREAKS the match (below). */\n register u8 *t0 __asm__(\"$8\"); // !FAKE: pin $8 \u2014 NEEDED DIFFERS (P36 rung B tus9)\n register u8 *t1 __asm__(\"$9\"); // !FAKE: pin $9 \u2014 NEEDED DIFFERS (P36 rung B tus9)\n s32 cnt;\n s32 mask;\n s32 shiftAmt;\n s32 *otp;\n s32 *potz, *psz0, *psz1;\n s32 idx0, idx1, idx2;\n s32 idx;\n s32 m;\n\n cnt = count;\n shiftAmt = shift;\n otp = ot;\n\n if (cnt == 0) {\n return a3;\n }\n\n /* Explicit pre-loop pointer temps, ordered ahead of mask/t0/t1: loop-invariant motion\n * APPENDS hoisted insns after the preheader's own statements, so leaving these implicit\n * emitted them last (`lui/ori, addiu t0, addiu t1, addiu sp+4/8/0xC`) -- the target is the\n * reverse order. */\n potz = &st[1];\n psz0 = &st[2];\n psz1 = &st[3];\n mask = 0xFFFFFF;\n t0 = (u8 *)a0 + 3;\n t1 = a3 + 4;\n\n do {\n idx0 = *(u16 *)(t0 + 0x11);\n idx1 = *(u16 *)(t0 + 0x13);\n idx2 = *(u16 *)(t0 + 0x15);\n\n gte_ldv3(&a1[idx0], &a1[idx1], &a1[idx2]);\n gte_rtpt();\n\n *(u32 *)(t1 + 8) = *(u32 *)(t0 + 1);\n *(u32 *)(t1 + 0x10) = *(u32 *)(t0 + 5);\n *(u32 *)(t1 + 0x18) = *(u32 *)(t0 + 9);\n\n gte_stflg(&st[0]);\n if (!(st[0] & ~0x1000)) {\n gte_nclip();\n gte_stopz(potz);\n if (st[1] > 0) {\n gte_stsxy3_ft3(a3);\n\n if (D_80078D88[0] & 0x8000) {\n gte_stsz3(psz0, psz1, &st[4]);\n /* `m` must NOT be the address-taken otz slot: assigning otz in each arm\n * makes gcc spill to sp+4 three times. The target keeps the running max\n * in $v1 and stores ONCE, so the max needs a plain (non-addressable) temp.\n * `st[2] > st[3]` (not `st[3] < st[2]`) is what loads sz0 first and emits\n * `slt $v0, $v1, $a2`. */\n if (st[2] > st[3]) {\n m = st[2];\n if (m < st[4]) m = st[4];\n } else {\n m = st[3];\n if (m < st[4]) m = st[4];\n }\n st[1] = m >> 2;\n } else {\n gte_avsz3();\n gte_stotz(potz);\n }\n\n *(u32 *)t1 = (*(u32 *)(t0 + 0xD) & mask) | ((u32)t0[0] << 24);\n t1 += 0x20;\n\n idx = st[1] >> shiftAmt;\n {\n u32 old = (u32)a3 & mask;\n /* `s32 *p = otp + idx;` -- writing `otp[idx]` inline emits the address\n * plus with the SCALED INDEX first (`addu $a0,$a0,$t8`); an explicit\n * pointer temp emits it base-first (`addu $a0,$t8,$a0`) like the target.\n * The second half of that fix is that `otp` must be an ordinary pseudo:\n * with `register s32 *otp __asm__(\"$24\")` local-alloc will not tie the\n * dying index register to the address destination and the chain lands in\n * $v0 instead of $a0. Base-first + unpinned base = the last instruction. */\n s32 *p = otp + idx;\n *(u32 *)a3 = (*p & mask) | 0x7000000;\n a3 += 0x20;\n *p = old;\n }\n }\n }\n\n t0 += 0x1C;\n } while (--cnt);\n\n return a3;\n}\n", "after_text": "void *func_800277DC(void *a0, SVECTOR800277DC *a1, void *a2, u8 *a3,\n s32 count, s32 shift, s32 *ot)\n{\n struct { s32 flag, otz, sz0, sz1, sz2; } g;\n struct { u8 pad[3]; u8 code; u32 rgb1, rgb2, term, rgb0; u16 i0, i1, i2, i3; } *src = a0;\n struct { u32 tag, rgb0, xy0, rgb1, xy1, rgb2, xy2, term; } *p = (void *)a3;\n s32 m;\n\n for (; count != 0; count--, src++) {\n gte_ldv3(&a1[src->i0], &a1[src->i1], &a1[src->i2]);\n gte_rtpt();\n p->rgb1 = src->rgb1;\n p->rgb2 = src->rgb2;\n p->term = src->term;\n gte_stflg(&g.flag);\n if (g.flag & 0xFFFFEFFF) {\n continue;\n }\n gte_nclip();\n gte_stopz(&g.otz);\n if (g.otz <= 0) {\n continue;\n }\n gte_stsxy3_ft3(p);\n if (D_80078D88[0] & 0x8000) {\n gte_stsz3(&g.sz0, &g.sz1, &g.sz2);\n if (g.sz0 > g.sz1) {\n m = g.sz0;\n if (m < g.sz2) m = g.sz2;\n } else {\n m = g.sz1;\n if (m < g.sz2) m = g.sz2;\n }\n g.otz = m >> 2;\n } else {\n gte_avsz3();\n gte_stotz(&g.otz);\n }\n p->rgb0 = (src->rgb0 & 0xFFFFFF) | ((u32)src->code << 24);\n {\n u32 *q = (u32 *)&ot[g.otz >> shift];\n p->tag = (*q & 0xFFFFFF) | 0x07000000;\n *q = (u32)p & 0xFFFFFF;\n }\n p++;\n }\n return p;\n}\n"} +{"ts": "2026-09-11 03:53:32", "label": "s104_e22", "rung": "E", "calib": {"head": "8733d36da", "stamp": "15956e4a96c4"}, "tu": "src/ov_SC06_029/ov_SC06_029_jr_8017C954.c", "fn": "func_8017C954", "addr": 2149042516, "aliases": null, "header": false, "includers": 0, "nhash_before": "8c7196cbabbd501745b1958962d403df83bbd598", "nhash_after": "6036a7d34f7fbe2880601f082ae41ee89e06fffa", "source": ".run/P36/agents/ov_SC06_029__func_8017C954/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.217, "objects": ["build/src/ov_SC06_029/ov_SC06_029_jr_8017C954.o"], "before_text": "void func_8017C954(s32 arg0)\n{\n typedef struct { u32 w0, w1, w2; } Prim;\n\n extern s32 func_800491EC(void);\n extern void func_800547D8(s32, MATRIX2 *);\n extern void func_80052E38(MATRIX2 *);\n extern u8 *D_800A5E60;\n extern u8 D_800A6610[];\n extern short D_800B9A02; /* TU-visible spelling (engine_core.h + ov_SC01_000.c col-0); unsigned access forced at use \u2014 \u00a78d sub-class (b) */\n extern s32 D_801DCCA0; /* fade/flash level driving both overlay colours */\n\n DVECTOR2 tmpxy[4];\n SVECTOR2 box[8];\n SVECTOR2 sxy[8];\n SVECTOR2 vv[4]; /* 0xA0..0xBF; only vv[3] is used (arm E vertex copy) */\n MATRIX2 mtx;\n struct { long otz, flag, opz, sz0, sz1, sz2, sz3; } g;\n\n s32 lim;\n u32 colA;\n u32 colB;\n u32 nprim;\n s32 nparts;\n s32 j;\n u32 i;\n Part *part;\n Prim *prim;\n u8 *pkt;\n u32 ot;\n u8 *vtx;\n u8 *va, *vb, *vc, *vd;\n u32 w, code;\n u32 wx, wy, wz;\n s32 xa32, xb32, t32;\n s32 xmn1, xmx1, xmn2, xmx2;\n s32 mnc, mxc;\n s16 my, mny, mx, mn;\n s32 d;\n u32 e;\n\n lim = func_800491EC() + *(s32 *)(arg0 + 0x64);\n func_800547D8(arg0 + 0x10, &mtx);\n func_80052E38(&mtx);\n\n pkt = D_800A5E60;\n ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];\n d = D_801DCCA0;\n colA = (d << 16) | (d << 8) | d;\n e = d * 2;\n if (e > 0xFF) e = 0xFF;\n colB = (e << 16) | (e << 8) | e;\n part = *(Part **)(arg0 + 0xC);\n nparts = *(s32 *)(*(s32 *)(arg0 + 8) + 8);\n vtx = *(u8 **)(*(s32 *)(arg0 + 8) + 0x10);\n\n for (j = 0; j < nparts; j++, part++) {\n wx = part->xx;\n mn = wx;\n mx = wx >> 16;\n wy = part->yy;\n mny = wy;\n my = wy >> 16;\n wz = part->zz;\n box[0].vx = mn; box[0].vy = mny;\n box[1].vx = mx; box[1].vy = mny;\n box[2].vx = mn; box[2].vy = mny;\n box[3].vx = mx; box[3].vy = mny;\n box[4].vx = mn; box[4].vy = my;\n box[5].vx = mx; box[5].vy = my;\n box[6].vx = mn; box[6].vy = my;\n box[7].vx = mx; box[7].vy = my;\n wy = wz >> 16;\n box[0].vz = wz;\n box[1].vz = wz;\n box[4].vz = wz;\n box[5].vz = wz;\n box[2].vz = wy;\n box[3].vz = wy;\n box[6].vz = wy;\n box[7].vz = wy;\n\n gte_ldv3c(&box[0]);\n gte_rtpt();\n gte_stsxy3(&sxy[0], &sxy[1], &sxy[2]);\n gte_ldv0(&box[3]);\n gte_rtps();\n gte_stsxy(&sxy[3]);\n gte_ldv3c(&box[4]);\n gte_rtpt();\n gte_stsxy3(&sxy[4], &sxy[5], &sxy[6]);\n gte_ldv0(&box[7]);\n gte_rtps();\n gte_stsxy(&sxy[7]);\n gte_stszotz(&g.otz);\n\n if (lim >= g.otz) {\n xa32 = sxy[0].vx;\n xb32 = sxy[1].vx;\n if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; }\n t32 = sxy[2].vx;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n t32 = sxy[3].vx;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n xa32 = sxy[4].vx;\n xb32 = sxy[5].vx;\n if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; }\n t32 = sxy[6].vx;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n t32 = sxy[7].vx;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n mnc = xmn1;\n if (xmn2 < xmn1) mnc = xmn2;\n mxc = xmx1;\n if (mxc < xmx2) mxc = xmx2;\n if ((s16)mxc >= -0xA0 && (s16)mnc < 0xA1) {\n xa32 = sxy[0].vy;\n xb32 = sxy[1].vy;\n if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; }\n t32 = sxy[2].vy;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n t32 = sxy[3].vy;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n xa32 = sxy[4].vy;\n xb32 = sxy[5].vy;\n if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; }\n t32 = sxy[6].vy;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n t32 = sxy[7].vy;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n mnc = xmn1;\n if (xmn2 < xmn1) mnc = xmn2;\n mxc = xmx1;\n if (mxc < xmx2) mxc = xmx2;\n if ((s16)mxc >= -0x78 && (s16)mnc < 0x79) {\n prim = (Prim *)part->prim;\n nprim = part->nprim;\n for (i = 0; i < nprim; i++, prim++) {\n w = prim->w1;\n va = vtx + (w & 0xFFFF);\n vb = vtx + (w >> 16);\n w = prim->w2;\n vc = vtx + (w & 0xFFFF);\n w = w >> 16;\n gte_ldv3(va, vb, vc);\n gte_rtpt();\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_nclip();\n code = w & 7;\n vd = vtx + (w & 0xFFF8);\n gte_stopz(&g.opz);\n if (g.opz > 0) {\n switch (code) {\n case 4:\n case 5:\n gte_stsxy3_f3(pkt);\n gte_stsz3(&g.sz0, &g.sz1, &g.sz2);\n if (((PolyF3 *)pkt)->x0 > ((PolyF3 *)pkt)->x1) {\n mx = ((PolyF3 *)pkt)->x0;\n mn = ((PolyF3 *)pkt)->x1;\n } else {\n mn = ((PolyF3 *)pkt)->x0;\n mx = ((PolyF3 *)pkt)->x1;\n }\n if (((PolyF3 *)pkt)->x2 > mx) mx = ((PolyF3 *)pkt)->x2;\n else if (((PolyF3 *)pkt)->x2 < mn) mn = ((PolyF3 *)pkt)->x2;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyF3 *)pkt)->y0 > ((PolyF3 *)pkt)->y1) {\n my = ((PolyF3 *)pkt)->y0;\n mny = ((PolyF3 *)pkt)->y1;\n } else {\n mny = ((PolyF3 *)pkt)->y0;\n my = ((PolyF3 *)pkt)->y1;\n }\n if (((PolyF3 *)pkt)->y2 > my) my = ((PolyF3 *)pkt)->y2;\n else if (((PolyF3 *)pkt)->y2 < mny) mny = ((PolyF3 *)pkt)->y2;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n if (g.sz0 > g.sz1) {\n za = g.sz0;\n if (za < g.sz2) za = g.sz2;\n } else {\n za = g.sz1;\n if (za < g.sz2) za = g.sz2;\n }\n g.opz = za;\n if (code != 4) g.opz = za + 0x200;\n ((PolyF3 *)pkt)->rgbc = prim->w0;\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x4000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x14;\n }\n }\n break;\n case 6:\n case 7:\n gte_stsxy3_ft3(pkt);\n gte_stsz3(&g.sz0, &g.sz1, &g.sz2);\n if (((PolyFT3 *)pkt)->x0 > ((PolyFT3 *)pkt)->x1) {\n mx = ((PolyFT3 *)pkt)->x0;\n mn = ((PolyFT3 *)pkt)->x1;\n } else {\n mn = ((PolyFT3 *)pkt)->x0;\n mx = ((PolyFT3 *)pkt)->x1;\n }\n if (((PolyFT3 *)pkt)->x2 > mx) mx = ((PolyFT3 *)pkt)->x2;\n else if (((PolyFT3 *)pkt)->x2 < mn) mn = ((PolyFT3 *)pkt)->x2;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyFT3 *)pkt)->y0 > ((PolyFT3 *)pkt)->y1) {\n my = ((PolyFT3 *)pkt)->y0;\n mny = ((PolyFT3 *)pkt)->y1;\n } else {\n mny = ((PolyFT3 *)pkt)->y0;\n my = ((PolyFT3 *)pkt)->y1;\n }\n if (((PolyFT3 *)pkt)->y2 > my) my = ((PolyFT3 *)pkt)->y2;\n else if (((PolyFT3 *)pkt)->y2 < mny) mny = ((PolyFT3 *)pkt)->y2;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n if (g.sz0 > g.sz1) {\n za = g.sz0;\n if (za < g.sz2) za = g.sz2;\n } else {\n za = g.sz1;\n if (za < g.sz2) za = g.sz2;\n }\n g.opz = za;\n if (code == 7) g.opz = za + 0x200;\n tp = (u32 *)prim->w0;\n ((PolyFT3 *)pkt)->rgbc = tp[0];\n ((PolyFT3 *)pkt)->uvc0 = tp[1];\n ((PolyFT3 *)pkt)->uvp1 = tp[2];\n ((PolyFT3 *)pkt)->uv2 = tp[3];\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x7000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x20;\n }\n }\n break;\n case 0:\n case 1:\n gte_stsxy3_f3(pkt);\n gte_ldv0(vd);\n gte_rtps();\n if (((PolyF4 *)pkt)->x0 > ((PolyF4 *)pkt)->x1) {\n mx = ((PolyF4 *)pkt)->x0;\n mn = ((PolyF4 *)pkt)->x1;\n } else {\n mn = ((PolyF4 *)pkt)->x0;\n mx = ((PolyF4 *)pkt)->x1;\n }\n if (((PolyF4 *)pkt)->x2 > mx) mx = ((PolyF4 *)pkt)->x2;\n else if (((PolyF4 *)pkt)->x2 < mn) mn = ((PolyF4 *)pkt)->x2;\n if (((PolyF4 *)pkt)->y0 > ((PolyF4 *)pkt)->y1) {\n my = ((PolyF4 *)pkt)->y0;\n mny = ((PolyF4 *)pkt)->y1;\n } else {\n mny = ((PolyF4 *)pkt)->y0;\n my = ((PolyF4 *)pkt)->y1;\n }\n if (((PolyF4 *)pkt)->y2 > my) my = ((PolyF4 *)pkt)->y2;\n else if (((PolyF4 *)pkt)->y2 < mny) mny = ((PolyF4 *)pkt)->y2;\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&((PolyF4 *)pkt)->x3);\n if (((PolyF4 *)pkt)->x3 < mn) mn = ((PolyF4 *)pkt)->x3;\n else if (mx < ((PolyF4 *)pkt)->x3) mx = ((PolyF4 *)pkt)->x3;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyF4 *)pkt)->y3 < mny) mny = ((PolyF4 *)pkt)->y3;\n else if (my < ((PolyF4 *)pkt)->y3) my = ((PolyF4 *)pkt)->y3;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n ((PolyF4 *)pkt)->rgbc = prim->w0;\n otp = (u32 *)(((za >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x5000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x18;\n }\n }\n }\n break;\n case 2:\n gte_stsxy3c(&tmpxy[0]);\n gte_ldv0(vd);\n gte_rtps();\n if (tmpxy[0].vx > tmpxy[1].vx) {\n mx = tmpxy[0].vx;\n mn = tmpxy[1].vx;\n } else {\n mn = tmpxy[0].vx;\n mx = tmpxy[1].vx;\n }\n if (tmpxy[2].vx > mx) mx = tmpxy[2].vx;\n else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx;\n if (tmpxy[0].vy > tmpxy[1].vy) {\n my = tmpxy[0].vy;\n mny = tmpxy[1].vy;\n } else {\n mny = tmpxy[0].vy;\n my = tmpxy[1].vy;\n }\n if (tmpxy[2].vy > my) my = tmpxy[2].vy;\n else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy;\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&((PolyFT4 *)pkt)->x3);\n if (((PolyFT4 *)pkt)->x3 < mn) mn = ((PolyFT4 *)pkt)->x3;\n else if (mx < ((PolyFT4 *)pkt)->x3) mx = ((PolyFT4 *)pkt)->x3;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyFT4 *)pkt)->y3 < mny) mny = ((PolyFT4 *)pkt)->y3;\n else if (my < ((PolyFT4 *)pkt)->y3) my = ((PolyFT4 *)pkt)->y3;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n u32 uvw;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n if (code == 3) g.opz = za + 0x200;\n *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0];\n *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1];\n *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2];\n tp = (u32 *)prim->w0;\n ((PolyFT4 *)pkt)->rgbc = tp[0];\n ((PolyFT4 *)pkt)->uvc0 = tp[1];\n ((PolyFT4 *)pkt)->uvp1 = tp[2];\n uvw = tp[3];\n ((PolyFT4 *)pkt)->uv2 = uvw;\n ((PolyFT4 *)pkt)->uv3 = uvw >> 16;\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x9000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x28;\n }\n }\n }\n break;\n case 3:\n gte_stsxy3c(&tmpxy[0]);\n vv[3] = *(SVECTOR2 *)vd;\n gte_ldv0(&vv[3]);\n gte_rtps();\n if (tmpxy[0].vx > tmpxy[1].vx) {\n mx = tmpxy[0].vx;\n mn = tmpxy[1].vx;\n } else {\n mn = tmpxy[0].vx;\n mx = tmpxy[1].vx;\n }\n if (tmpxy[2].vx > mx) mx = tmpxy[2].vx;\n else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx;\n if (tmpxy[0].vy > tmpxy[1].vy) {\n my = tmpxy[0].vy;\n mny = tmpxy[1].vy;\n } else {\n mny = tmpxy[0].vy;\n my = tmpxy[1].vy;\n }\n if (tmpxy[2].vy > my) my = tmpxy[2].vy;\n else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy;\n /* L1: zero-byte $v1 conflict dial -- keeps my/mny off $v1 so the\n * my/mny/mx/mn quad lands on $a2/$a3/$t0/$t1 (see header). */\n __asm__ __volatile__ (\"\" ::: \"$3\"); // !FAKE: barrier \u2014 NEEDED DIFFERS (P36 rung B tus10)\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&tmpxy[3]);\n if (tmpxy[3].vx < mn) mn = tmpxy[3].vx;\n else if (mx < tmpxy[3].vx) mx = tmpxy[3].vx;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (tmpxy[3].vy < mny) mny = tmpxy[3].vy;\n else if (my < tmpxy[3].vy) my = tmpxy[3].vy;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n u32 uvw;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0];\n *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1];\n *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2];\n *(u32 *)&((PolyFT4 *)pkt)->x3 = *(u32 *)&tmpxy[3];\n tp = (u32 *)prim->w0;\n ((PolyFT4 *)pkt)->rgbc = colA | 0x2E000000;\n ((PolyFT4 *)pkt)->uvc0 = tp[1];\n ((PolyFT4 *)pkt)->uvp1 = tp[2];\n uvw = tp[3];\n ((PolyFT4 *)pkt)->uv2 = uvw;\n ((PolyFT4 *)pkt)->uv3 = uvw >> 16;\n {\n u32 *op1 = (u32 *)(((za >> 2) << 2) + ot);\n *(u32 *)pkt = (*op1 & 0xFFFFFF) | 0x9000000;\n *op1 = (*op1 & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n }\n pkt += 0x28;\n pkt[3] = 6;\n *(u32 *)(pkt + 8) = colB | 0x2A000000;\n *(u32 *)(pkt + 0xC) = *(u32 *)&tmpxy[0];\n *(u32 *)(pkt + 4) = 0xE1000040;\n *(u32 *)(pkt + 0x10) = *(u32 *)&tmpxy[1];\n *(u32 *)(pkt + 0x14) = *(u32 *)&tmpxy[2];\n *(u32 *)(pkt + 0x18) = *(u32 *)&tmpxy[3];\n {\n u32 *op2 = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*op2 & 0xFFFFFF) | 0x6000000;\n *op2 = (*op2 & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n }\n pkt += 0x1C;\n }\n }\n }\n break;\n }\n }\n }\n }\n }\n }\n }\n }\n D_800A5E60 = pkt;\n}\n", "after_text": "void func_8017C954(s32 arg0)\n{\n typedef struct { u32 w0, w1, w2; } Prim;\n\n extern s32 func_800491EC(void);\n extern void func_800547D8(s32, MATRIX2 *);\n extern void func_80052E38(MATRIX2 *);\n extern u8 *D_800A5E60;\n extern u8 D_800A6610[];\n extern short D_800B9A02; /* TU-visible spelling (engine_core.h + ov_SC01_000.c col-0); unsigned access forced at use \u2014 \u00a78d sub-class (b) */\n extern s32 D_801DCCA0; /* fade/flash level driving both overlay colours */\n\n DVECTOR2 tmpxy[4];\n SVECTOR2 box[8];\n SVECTOR2 sxy[8];\n SVECTOR2 vv[4]; /* 0xA0..0xBF; only vv[3] is used (arm E vertex copy) */\n MATRIX2 mtx;\n struct { long otz, flag, opz, sz0, sz1, sz2, sz3; } g;\n\n s32 lim;\n u32 colA;\n u32 colB;\n u32 nprim;\n s32 nparts;\n s32 j;\n u32 i;\n Part *part;\n Prim *prim;\n u8 *pkt;\n u32 ot;\n u8 *vtx;\n u8 *va, *vb, *vc, *vd;\n u32 w, code;\n u32 wx, wy, wz;\n s16 wq; /* P36 S104 e22: the box's high z half, its own s16 (see mechanism.md) */\n s32 xa32, xb32, t32;\n s32 xmn1, xmx1, xmn2, xmx2;\n s32 mnc, mxc;\n s16 my, mny, mx, mn;\n s32 d;\n u32 e;\n\n lim = func_800491EC() + *(s32 *)(arg0 + 0x64);\n func_800547D8(arg0 + 0x10, &mtx);\n func_80052E38(&mtx);\n\n pkt = D_800A5E60;\n ot = (u32)&D_800A6610[(*(u16 *)&D_800B9A02) << 14];\n d = D_801DCCA0;\n colA = (d << 16) | (d << 8) | d;\n e = d * 2;\n if (e > 0xFF) e = 0xFF;\n colB = (e << 16) | (e << 8) | e;\n part = *(Part **)(arg0 + 0xC);\n nparts = *(s32 *)(*(s32 *)(arg0 + 8) + 8);\n vtx = *(u8 **)(*(s32 *)(arg0 + 8) + 0x10);\n\n for (j = 0; j < nparts; j++, part++) {\n wx = part->xx;\n mn = wx;\n mx = wx >> 16;\n wy = part->yy;\n mny = wy;\n my = wy >> 16;\n wz = part->zz;\n box[0].vx = mn; box[0].vy = mny;\n box[1].vx = mx; box[1].vy = mny;\n box[2].vx = mn; box[2].vy = mny;\n box[3].vx = mx; box[3].vy = mny;\n box[4].vx = mn; box[4].vy = my;\n box[5].vx = mx; box[5].vy = my;\n box[6].vx = mn; box[6].vy = my;\n box[7].vx = mx; box[7].vy = my;\n wq = wz >> 16;\n box[0].vz = wz;\n box[1].vz = wz;\n box[4].vz = wz;\n box[5].vz = wz;\n box[2].vz = wq;\n box[3].vz = wq;\n box[6].vz = wq;\n box[7].vz = wq;\n\n gte_ldv3c(&box[0]);\n gte_rtpt();\n gte_stsxy3(&sxy[0], &sxy[1], &sxy[2]);\n gte_ldv0(&box[3]);\n gte_rtps();\n gte_stsxy(&sxy[3]);\n gte_ldv3c(&box[4]);\n gte_rtpt();\n gte_stsxy3(&sxy[4], &sxy[5], &sxy[6]);\n gte_ldv0(&box[7]);\n gte_rtps();\n gte_stsxy(&sxy[7]);\n gte_stszotz(&g.otz);\n\n if (lim >= g.otz) {\n xa32 = sxy[0].vx;\n xb32 = sxy[1].vx;\n if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; }\n t32 = sxy[2].vx;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n t32 = sxy[3].vx;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n xa32 = sxy[4].vx;\n xb32 = sxy[5].vx;\n if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; }\n t32 = sxy[6].vx;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n t32 = sxy[7].vx;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n mnc = xmn1;\n if (xmn2 < xmn1) mnc = xmn2;\n mxc = xmx1;\n if (mxc < xmx2) mxc = xmx2;\n if ((s16)mxc >= -0xA0 && (s16)mnc < 0xA1) {\n xa32 = sxy[0].vy;\n xb32 = sxy[1].vy;\n if (xb32 < xa32) { xmx1 = xa32; xmn1 = xb32; } else { xmn1 = xa32; xmx1 = xb32; }\n t32 = sxy[2].vy;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n t32 = sxy[3].vy;\n if (xmx1 < t32) xmx1 = t32; else if (t32 < xmn1) xmn1 = t32;\n xa32 = sxy[4].vy;\n xb32 = sxy[5].vy;\n if (xb32 < xa32) { xmx2 = xa32; xmn2 = xb32; } else { xmn2 = xa32; xmx2 = xb32; }\n t32 = sxy[6].vy;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n t32 = sxy[7].vy;\n if (xmx2 < t32) xmx2 = t32; else if (t32 < xmn2) xmn2 = t32;\n mnc = xmn1;\n if (xmn2 < xmn1) mnc = xmn2;\n mxc = xmx1;\n if (mxc < xmx2) mxc = xmx2;\n if ((s16)mxc >= -0x78 && (s16)mnc < 0x79) {\n prim = (Prim *)part->prim;\n nprim = part->nprim;\n for (i = 0; i < nprim; i++, prim++) {\n w = prim->w1;\n va = vtx + (w & 0xFFFF);\n vb = vtx + (w >> 16);\n w = prim->w2;\n vc = vtx + (w & 0xFFFF);\n w = w >> 16;\n gte_ldv3(va, vb, vc);\n gte_rtpt();\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_nclip();\n code = w & 7;\n vd = vtx + (w & 0xFFF8);\n gte_stopz(&g.opz);\n if (g.opz > 0) {\n switch (code) {\n case 4:\n case 5:\n gte_stsxy3_f3(pkt);\n gte_stsz3(&g.sz0, &g.sz1, &g.sz2);\n if (((PolyF3 *)pkt)->x0 > ((PolyF3 *)pkt)->x1) {\n mx = ((PolyF3 *)pkt)->x0;\n mn = ((PolyF3 *)pkt)->x1;\n } else {\n mn = ((PolyF3 *)pkt)->x0;\n mx = ((PolyF3 *)pkt)->x1;\n }\n if (((PolyF3 *)pkt)->x2 > mx) mx = ((PolyF3 *)pkt)->x2;\n else if (((PolyF3 *)pkt)->x2 < mn) mn = ((PolyF3 *)pkt)->x2;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyF3 *)pkt)->y0 > ((PolyF3 *)pkt)->y1) {\n my = ((PolyF3 *)pkt)->y0;\n mny = ((PolyF3 *)pkt)->y1;\n } else {\n mny = ((PolyF3 *)pkt)->y0;\n my = ((PolyF3 *)pkt)->y1;\n }\n if (((PolyF3 *)pkt)->y2 > my) my = ((PolyF3 *)pkt)->y2;\n else if (((PolyF3 *)pkt)->y2 < mny) mny = ((PolyF3 *)pkt)->y2;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n if (g.sz0 > g.sz1) {\n za = g.sz0;\n if (za < g.sz2) za = g.sz2;\n } else {\n za = g.sz1;\n if (za < g.sz2) za = g.sz2;\n }\n g.opz = za;\n if (code != 4) g.opz = za + 0x200;\n ((PolyF3 *)pkt)->rgbc = prim->w0;\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x4000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x14;\n }\n }\n break;\n case 6:\n case 7:\n gte_stsxy3_ft3(pkt);\n gte_stsz3(&g.sz0, &g.sz1, &g.sz2);\n if (((PolyFT3 *)pkt)->x0 > ((PolyFT3 *)pkt)->x1) {\n mx = ((PolyFT3 *)pkt)->x0;\n mn = ((PolyFT3 *)pkt)->x1;\n } else {\n mn = ((PolyFT3 *)pkt)->x0;\n mx = ((PolyFT3 *)pkt)->x1;\n }\n if (((PolyFT3 *)pkt)->x2 > mx) mx = ((PolyFT3 *)pkt)->x2;\n else if (((PolyFT3 *)pkt)->x2 < mn) mn = ((PolyFT3 *)pkt)->x2;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyFT3 *)pkt)->y0 > ((PolyFT3 *)pkt)->y1) {\n my = ((PolyFT3 *)pkt)->y0;\n mny = ((PolyFT3 *)pkt)->y1;\n } else {\n mny = ((PolyFT3 *)pkt)->y0;\n my = ((PolyFT3 *)pkt)->y1;\n }\n if (((PolyFT3 *)pkt)->y2 > my) my = ((PolyFT3 *)pkt)->y2;\n else if (((PolyFT3 *)pkt)->y2 < mny) mny = ((PolyFT3 *)pkt)->y2;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n if (g.sz0 > g.sz1) {\n za = g.sz0;\n if (za < g.sz2) za = g.sz2;\n g.opz = za;\n } else {\n za = g.sz1;\n if (za < g.sz2) za = g.sz2;\n g.opz = za;\n }\n if (code == 7) g.opz = za + 0x200;\n tp = (u32 *)prim->w0;\n ((PolyFT3 *)pkt)->rgbc = tp[0];\n ((PolyFT3 *)pkt)->uvc0 = tp[1];\n ((PolyFT3 *)pkt)->uvp1 = tp[2];\n ((PolyFT3 *)pkt)->uv2 = tp[3];\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x7000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x20;\n }\n }\n break;\n case 0:\n case 1:\n gte_stsxy3_f3(pkt);\n gte_ldv0(vd);\n gte_rtps();\n if (((PolyF4 *)pkt)->x0 > ((PolyF4 *)pkt)->x1) {\n mx = ((PolyF4 *)pkt)->x0;\n mn = ((PolyF4 *)pkt)->x1;\n } else {\n mn = ((PolyF4 *)pkt)->x0;\n mx = ((PolyF4 *)pkt)->x1;\n }\n if (((PolyF4 *)pkt)->x2 > mx) mx = ((PolyF4 *)pkt)->x2;\n else if (((PolyF4 *)pkt)->x2 < mn) mn = ((PolyF4 *)pkt)->x2;\n if (((PolyF4 *)pkt)->y0 > ((PolyF4 *)pkt)->y1) {\n my = ((PolyF4 *)pkt)->y0;\n mny = ((PolyF4 *)pkt)->y1;\n } else {\n mny = ((PolyF4 *)pkt)->y0;\n my = ((PolyF4 *)pkt)->y1;\n }\n if (((PolyF4 *)pkt)->y2 > my) my = ((PolyF4 *)pkt)->y2;\n else if (((PolyF4 *)pkt)->y2 < mny) mny = ((PolyF4 *)pkt)->y2;\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&((PolyF4 *)pkt)->x3);\n if (((PolyF4 *)pkt)->x3 < mn) mn = ((PolyF4 *)pkt)->x3;\n else if (mx < ((PolyF4 *)pkt)->x3) mx = ((PolyF4 *)pkt)->x3;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyF4 *)pkt)->y3 < mny) mny = ((PolyF4 *)pkt)->y3;\n else if (my < ((PolyF4 *)pkt)->y3) my = ((PolyF4 *)pkt)->y3;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n ((PolyF4 *)pkt)->rgbc = prim->w0;\n otp = (u32 *)(((za >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x5000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x18;\n }\n }\n }\n break;\n case 2:\n gte_stsxy3c(&tmpxy[0]);\n gte_ldv0(vd);\n gte_rtps();\n if (tmpxy[0].vx > tmpxy[1].vx) {\n mx = tmpxy[0].vx;\n mn = tmpxy[1].vx;\n } else {\n mn = tmpxy[0].vx;\n mx = tmpxy[1].vx;\n }\n if (tmpxy[2].vx > mx) mx = tmpxy[2].vx;\n else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx;\n if (tmpxy[0].vy > tmpxy[1].vy) {\n my = tmpxy[0].vy;\n mny = tmpxy[1].vy;\n } else {\n mny = tmpxy[0].vy;\n my = tmpxy[1].vy;\n }\n if (tmpxy[2].vy > my) my = tmpxy[2].vy;\n else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy;\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&((PolyFT4 *)pkt)->x3);\n if (((PolyFT4 *)pkt)->x3 < mn) mn = ((PolyFT4 *)pkt)->x3;\n else if (mx < ((PolyFT4 *)pkt)->x3) mx = ((PolyFT4 *)pkt)->x3;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (((PolyFT4 *)pkt)->y3 < mny) mny = ((PolyFT4 *)pkt)->y3;\n else if (my < ((PolyFT4 *)pkt)->y3) my = ((PolyFT4 *)pkt)->y3;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n u32 uvw;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n if (code == 3) g.opz = za + 0x200;\n *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0];\n *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1];\n *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2];\n tp = (u32 *)prim->w0;\n ((PolyFT4 *)pkt)->rgbc = tp[0];\n ((PolyFT4 *)pkt)->uvc0 = tp[1];\n ((PolyFT4 *)pkt)->uvp1 = tp[2];\n uvw = tp[3];\n ((PolyFT4 *)pkt)->uv2 = uvw;\n ((PolyFT4 *)pkt)->uv3 = uvw >> 16;\n otp = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*otp & 0xFFFFFF) | 0x9000000;\n *otp = (*otp & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n pkt += 0x28;\n }\n }\n }\n break;\n case 3:\n gte_stsxy3c(&tmpxy[0]);\n vv[3] = *(SVECTOR2 *)vd;\n gte_ldv0(&vv[3]);\n gte_rtps();\n if (tmpxy[0].vx > tmpxy[1].vx) {\n mx = tmpxy[0].vx;\n mn = tmpxy[1].vx;\n } else {\n mn = tmpxy[0].vx;\n mx = tmpxy[1].vx;\n }\n if (tmpxy[2].vx > mx) mx = tmpxy[2].vx;\n else if (tmpxy[2].vx < mn) mn = tmpxy[2].vx;\n if (tmpxy[0].vy > tmpxy[1].vy) {\n my = tmpxy[0].vy;\n mny = tmpxy[1].vy;\n } else {\n mny = tmpxy[0].vy;\n my = tmpxy[1].vy;\n }\n if (tmpxy[2].vy > my) my = tmpxy[2].vy;\n else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy;\n gte_stflg(&g.flag);\n if (!(g.flag & 0x7F85E000)) {\n gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);\n gte_stsxy((long *)&tmpxy[3]);\n if (tmpxy[3].vx < mn) mn = tmpxy[3].vx;\n else if (mx < tmpxy[3].vx) mx = tmpxy[3].vx;\n if (mx >= -0xA0 && mn < 0xA1) {\n if (tmpxy[3].vy < mny) mny = tmpxy[3].vy;\n else if (my < tmpxy[3].vy) my = tmpxy[3].vy;\n if (my >= -0x78 && mny < 0x79) {\n s32 za, zb;\n u32 *otp;\n u32 *tp;\n u32 uvw;\n zb = g.sz2;\n if (zb < g.sz3) zb = g.sz3;\n za = g.sz0;\n if (za < g.sz1) za = g.sz1;\n if (za < zb) za = zb;\n g.opz = za;\n *(u32 *)&((PolyFT4 *)pkt)->x0 = *(u32 *)&tmpxy[0];\n *(u32 *)&((PolyFT4 *)pkt)->x1 = *(u32 *)&tmpxy[1];\n *(u32 *)&((PolyFT4 *)pkt)->x2 = *(u32 *)&tmpxy[2];\n *(u32 *)&((PolyFT4 *)pkt)->x3 = *(u32 *)&tmpxy[3];\n tp = (u32 *)prim->w0;\n ((PolyFT4 *)pkt)->rgbc = colA | 0x2E000000;\n ((PolyFT4 *)pkt)->uvc0 = tp[1];\n ((PolyFT4 *)pkt)->uvp1 = tp[2];\n uvw = tp[3];\n ((PolyFT4 *)pkt)->uv2 = uvw;\n ((PolyFT4 *)pkt)->uv3 = uvw >> 16;\n {\n u32 *op1 = (u32 *)(((za >> 2) << 2) + ot);\n *(u32 *)pkt = (*op1 & 0xFFFFFF) | 0x9000000;\n *op1 = (*op1 & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n }\n pkt += 0x28;\n pkt[3] = 6;\n *(u32 *)(pkt + 8) = colB | 0x2A000000;\n *(u32 *)(pkt + 0xC) = *(u32 *)&tmpxy[0];\n *(u32 *)(pkt + 4) = 0xE1000040;\n *(u32 *)(pkt + 0x10) = *(u32 *)&tmpxy[1];\n *(u32 *)(pkt + 0x14) = *(u32 *)&tmpxy[2];\n *(u32 *)(pkt + 0x18) = *(u32 *)&tmpxy[3];\n {\n u32 *op2 = (u32 *)(((g.opz >> 2) << 2) + ot);\n *(u32 *)pkt = (*op2 & 0xFFFFFF) | 0x6000000;\n *op2 = (*op2 & 0xFF000000) | ((u32)pkt & 0xFFFFFF);\n }\n pkt += 0x1C;\n }\n }\n }\n break;\n }\n }\n }\n }\n }\n }\n }\n }\n D_800A5E60 = pkt;\n}\n"} diff --git a/src/ov_SC06_029/ov_SC06_029_jr_8017C954.c b/src/ov_SC06_029/ov_SC06_029_jr_8017C954.c index e7a22b865..c9d216889 100644 --- a/src/ov_SC06_029/ov_SC06_029_jr_8017C954.c +++ b/src/ov_SC06_029/ov_SC06_029_jr_8017C954.c @@ -2895,6 +2895,7 @@ void func_8017C954(s32 arg0) u8 *va, *vb, *vc, *vd; u32 w, code; u32 wx, wy, wz; + s16 wq; /* P36 S104 e22: the box's high z half, its own s16 (see mechanism.md) */ s32 xa32, xb32, t32; s32 xmn1, xmx1, xmn2, xmx2; s32 mnc, mxc; @@ -2933,15 +2934,15 @@ void func_8017C954(s32 arg0) box[5].vx = mx; box[5].vy = my; box[6].vx = mn; box[6].vy = my; box[7].vx = mx; box[7].vy = my; - wy = wz >> 16; + wq = wz >> 16; box[0].vz = wz; box[1].vz = wz; box[4].vz = wz; box[5].vz = wz; - box[2].vz = wy; - box[3].vz = wy; - box[6].vz = wy; - box[7].vz = wy; + box[2].vz = wq; + box[3].vz = wq; + box[6].vz = wq; + box[7].vz = wq; gte_ldv3c(&box[0]); gte_rtpt(); @@ -3088,11 +3089,12 @@ void func_8017C954(s32 arg0) if (g.sz0 > g.sz1) { za = g.sz0; if (za < g.sz2) za = g.sz2; + g.opz = za; } else { za = g.sz1; if (za < g.sz2) za = g.sz2; + g.opz = za; } - g.opz = za; if (code == 7) g.opz = za + 0x200; tp = (u32 *)prim->w0; ((PolyFT3 *)pkt)->rgbc = tp[0]; @@ -3240,9 +3242,6 @@ void func_8017C954(s32 arg0) } if (tmpxy[2].vy > my) my = tmpxy[2].vy; else if (tmpxy[2].vy < mny) mny = tmpxy[2].vy; - /* L1: zero-byte $v1 conflict dial -- keeps my/mny off $v1 so the - * my/mny/mx/mn quad lands on $a2/$a3/$t0/$t1 (see header). */ - __asm__ __volatile__ ("" ::: "$3"); // !FAKE: barrier — NEEDED DIFFERS (P36 rung B tus10) gte_stflg(&g.flag); if (!(g.flag & 0x7F85E000)) { gte_stsz4(&g.sz0, &g.sz1, &g.sz2, &g.sz3);