Files
BFM-decomp/cookbook/C0467.md
T

2.0 KiB

§419 ★★★ — WHEN A PIN IS IMPOSSIBLE, WIN THE local-alloc DENSITY CONTEST INSTEAD (P31 S71; byte-proven ov_SC01_000/func_8017DD04, 297 ins)

Why the pin could not work. The obvious lever — pin the 0x80 constant to $7 — LOSES its sched1 birthing boost, because $a3 (and $a2) are ALSO set by this function's own call-argument copies, so reg_n_sets == 2. A hard-register pin on an argument register is unavailable to any function that passes arguments in it. $6/$7 therefore have to come out of local-alloc density, unpinned.

The density arithmetic, which is computable before you try anything. local-alloc ranks by refs / live_length:

pseudo refs live length density
0x80 13 319 4890
0xFFFFFF 9 345 3130

0x80 out-densities its rival and takes $6 — a pure $a2↔$a3 swap, 24 instructions wrong.

The lever: buy references, not a register. One SIX-INPUT zero-byte asm at the blk3/blk4 boundary — __asm__("" :: "r"(mlo), "r"(mlo), "r"(mlo), "r"(mlo), "r"(mlo), "r"(mlo)) — adds 6 references to mlo and nothing to the output. Density becomes 5217 > 4890, so mlo takes $6, 0x80 falls to $7, and its boost survives because it was never pinned. The boundary matters: pick the ONE cut no hoisted constant crosses, or you change the live lengths you are trying to exploit.

MEASURED INERT on this function: pinning mlo = $6 (cse never substitutes a hard register for a bitfield constant) or it explodes (+3, $s0); and a dead hard-register copy as a "register suggestion" is simply deleted by flow.

The general law. A register assignment you cannot pin, you can still win — by changing the density ranking rather than the register. Reference count is a dial (zero-byte asm inputs) and live length is a dial (where you place the barrier); local-alloc's ordering is arithmetic on the two, so compute it from the -df/-dl dumps and aim, instead of trying pins that a call-argument register structurally forbids.