Files
BFM-decomp/cookbook/C0465.md
T

1.9 KiB

§417 ★★★ — A REGISTER PIN CAN BLOCK jump.c's SELECT COLLAPSE, AND UNPINNING THEN EXPOSES A cse SKIP-BLOCKS MERGE (P31 S71; byte-proven ov_SC03_013/func_8017E6F4, 182 ins)

Two compiler passes in a chain, and the first agent misattributed the second to the first. The prior attempt sat at a 3-instruction residual with a $3 pin on a select's result and concluded that "unpinning costs +2". Both halves were wrong in an instructive way.

1. The pin blocked jump.c. A PINNED select arm expands as ior + a copy — TWO insns — so jump.c:728's x = b; if (c) x = a; collapse cannot fire, and reorg emits bne/ori/move. Removing the pin lets the collapse happen. A hard-register pin is not neutral to the RTL optimisers: it changes the INSN COUNT of the pattern they pattern-match on.

2. Unpinning then exposed a different pass. With every select collapsed, cse's cse_end_of_basic_block skip_blocks path now walks from the first D_80184D2C[idx] read all the way to the second and CSEs the symbol_ref into $s3 — the +2 the earlier agent blamed on the unpinning. The residual moved; it did not grow.

The fix is to end the cse block, not to restore the pin: put a REAL diamond between the two uses (a vol clamp written as if/else, whose IOR arm is uncollapsible), keep register vol __asm__("$5") so both arms land in $a1, and spell the absolute value as if ((s16)w < 0) w = -w; e = w;. Four compiles from there.

The general law. When removing a lever moves the residual instead of shrinking it, the new residual is a DIFFERENT PASS — attribute it before re-adding the lever. "Removing X costs +2" is almost always "removing X unblocked pass A, and pass B now fires"; re-adding X re-blocks A and hides B again, which is how a function plateaus for three attempts. The instrument is the pass dump (-dL, -dj, -dS), not another guess.