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 onukills the boost and hoists theandi/sllfour slots early (+6 SCHEDULE).t = u + s[0x14];— right schedule, buttallocates$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).