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.