Files
BFM-decomp/cookbook/C0260.md
T

2.3 KiB

§239 — TWO-STATEMENT INTEGER-SPACE MATERIALISATION REORDERS la vs sll; AND THE PLUS-TREE OPERAND ORDER (P31 S58b)

§164-01/§164-02 explain why parenthesisation and operand order are inert for &sym[i]. They are not inert for the two constructs below, and both were found the hard way.

1. TO PUT THE BASE lui/addiu BEFORE THE INDEX sll, LEAVE POINTER SPACE. func_80186304 (ov_SC02_005, 72/72): every natural &D_xxx[i] / pointer-index spelling emits index-sll first, then lui/addiu (cse qty_const swap, §164-02). The target emits base first. The fix is a two-statement integer-space materialisation:

base = (s32)&sym;                       /* lui/addiu here */
p    = (void **)(base + i * 8);         /* sll, then addu */

That gets the expansion order right, but first-fit then assigned base→$a0/index→$v0; a short-lived register s32 base __asm__("$2") (never live across a call, so §42e-safe) forced base→$v0, index→$v1, and the card snapped to MATCH. This is the cheap hard-reg fix when only a REGALLOC-PERM remains after the order is right.

2. FOR A REGISTER-HELD BASE, THE PLUS-TREE OPERAND ORDER IS THE DIAL. func_801A5C44 (md_SC07_003, 41/41): the target's addu $v1,$v1,$s1 ; lhu $v1,0x2($v1) appears only when the C spells the shifted index term FIRST: ((idx << 2) + base + 2). Writing base + (idx << 2) emitted addu $v1,$s1,$v1 on one arm and, worse, folded the +2 into the address so gcc reused $s1 itself (addu $s1,$s1,$v1 ; lhu 2($s1)), clobbering a callee-saved register. §195-K's array-of-struct-vs- address dichotomy covers global symbol bases; for a pointer local the dial is operand order.

3. AND FOR AN OT/TABLE POINTER, INTEGER FORM BEATS POINTER ARITHMETIC. func_80185910 (ov_SC02_000/ov_SC02_003, 140/140): (otz << 2) + (s32)tbl gives lw $v1,sp / sll $v1,2 / addu $v1,$v1,$s1; the tbl + otz pointer form misallocates. Same finding on func_80183478 (ov_SC06_029): folding the scale into a single initializer (idx = load * 8) makes cc1 expand the index pseudo first, pinning it to $a0 and leaving $a2 for the counter.

BOUNDARY. None of this applies while the base is a plain global symbol reached by &sym[i] — there §164-01/§164-02 still hold and the spelling is inert.