Files
BFM-decomp/cookbook/C0255.md
T

2.8 KiB

§234 — CONSTANT MATERIALISATION: THE STORE LVALUE'S SIGNEDNESS PICKS addiu vs li/ori (P31 S58b)

The law. For a halfword (or byte) store of a compile-time constant, gcc-2.7.2 chooses the materialising instruction from the declared signedness of the LVALUE being stored through, not from how the literal is written in C:

you write lvalue emitted
*(s16*)p = -K; signed addiu $rt,$zero,-K (sign-extended)
*(u16*)p = -K; or = 0xFFFF-K+1; unsigned li/ori $rt,$zero,0xFF.. (zero-extended)
*(u16*)p = K; with bit 15 set (0x8000, 0xAA10, 0xC006, 0xC010) unsigned ori $rt,$zero,K
*(s16*)p = K; with bit 15 set signed li/addiu of the sign-extended pattern — wrong
K with bit 15 clear (0x7FFF, 0x3000, 0x40) either addiu — the dial is inert

BYTE-VERIFIED. asm/ov_SC06_029/.../func_80187CE4.s reads lhu $v0,0xA($a0) … addiu $v0,$zero,-0x82 … sh $v0,0xA($a0): the same field is read unsigned and written signed, so the read spelling and the store spelling are independent (this is §227's law seen from the constant side). asm/ov_SC03_091/.../func_80187EF8.s carries ori $v0,$zero,0x8000 three lines from addiu $v0,$zero,0x7FFF — the two halves of the table above, in one basic block.

THE DIAL EXTENDS TO A LOCAL ARRAY'S ELEMENT TYPE. func_80187F18 (ov_SC02_017): the stack message buffer had to be s16[], not u16[], purely so the -2 element emitted addiu $v0,$zero,-0x2 instead of li $v0,0xfffe; the callee still takes u16* (cast at the call site). func_80183750 (ov_SC04_004) is the same card in the same direction. func_8018BE74/func_80183AF4 show the opposite: keep the array u16[] to get ori.

AND TO A GLOBAL'S EXTERN. func_80186044 (ov_SC06_029): the atlas says D_80126B62 is u16, but u16 emitted ori $v0,$zero,0xff00/0xfa80 for the clamps while the target has addiu $v0,$zero,-0x100/-0x580. The fix is a block-scoped extern s16 D_80126B62; shadowing the file-scope u16 — legal C89, decl-only, zero bytes, and it does not disturb any other function in the TU.

Cards. func_80180CB0 (ov_SC07_001), func_8017FA94 (ov_SC07_002), func_80181000 (ov_SC01_001), func_80183418/func_8017F780 (ov_SC02_027), func_80181810 (ov_SC04_002), func_8018A0E4, func_8018876C, func_8017F88C (ov_SC05_001), func_801863E0/func_8017D9CC, func_80180424 (ov_SC06_022), func_80182810 (ov_SC02_005, unsigned suffix 0x38000u for lui+ori), func_80187FD8 (ov_SC03_090, |= 0xD8000000 not |= -0x80000000).

BOUNDARY. Word stores are immune (lui/ori is chosen by the constant's low half alone), and a constant with bit 15 clear is immune in both directions. Do not reach for this when the residual is a whole extra instruction — that is §251 or §239, not this.