Files
BFM-decomp/cookbook/C0458.md
T

2.0 KiB

§410 ★★★ — COPY THEN ACCUMULATE ON THE COPY: resolving the birthing-boost vs register-allocation dilemma (P31 S71; byte-proven ov_SC04_015/func_8017EB78, 98 ins)

The dilemma, stated exactly. A value u must (a) end up in $s2 as the destination of an addu $s2,$s2,$v0 — which wants an IN-PLACE u += w — and (b) keep its sched1 LAUNCH boost, which requires u's pseudo to have exactly ONE set (birthing_insn_p). Those are incompatible:

  • u += s[0x14]; — right register, but a SECOND set on u kills the boost and hoists the andi/sll four slots early (+6 SCHEDULE).
  • t = u + s[0x14]; — right schedule, but t allocates $v0, not $s2.

The lever: introduce a copy and accumulate on the COPY.

u2 = u;                 /* u keeps ONE set -> birthing boost intact, sll stays at idx 29 */
u2 += s[0x14];          /* u2 is an in-place RMW pseudo ... */
p[0x24] = u2;           /* ... which local-alloc coalesces onto $s2 THROUGH THE DYING COPY */

u stays single-set so the scheduler still treats it as birthing; u2 is a read-modify-write pseudo whose live range starts at a copy that dies immediately, and local-alloc coalesces it onto $s2. Both constraints satisfied by one extra statement. This is the inverse of §350: there the fix was to remove a copy, here it is to add one.

Its companion — the commutative-operand order dial. A direct p[0x14] = u + s[0x14]; emits the plus with the operands the wrong way round. A named temp fixes it: tA = u + s[0x14]; p[0x14] = tA; gives plus(u, load) rather than plus(load, u).

MEASURED INERT on this function — do not re-try them (the value of a refutation list, §406's lesson applied): register pins on $18/$s2 (they force $s4 live, +2 drift) · statement reorder of u = … (§3-T2 / §49 LUID — sll priority is scheduler-internal, §307) · every __asm__("") fence placement · folding u into X. Frame came out at 0x50 via s32 pad[10] (§164-53), and the two-u8-copy locals were read off the TU neighbour func_8017E830 (§194-E).