Files
BFM-decomp/cookbook/C0155.md
T

2.1 KiB

§144 — THE LITERAL'S SPELLING PICKS THE IMMEDIATE ENCODING (P30 S40 wave 1, func_801822E0)

A new, byte-proven gcc-2.7.2 idiom, found by a wave agent on an 85-ins exemplar.

A byte counter stored through an sb was diffing on one instruction's immediate field only:

target :  addiu $v0, $v1, 0xFF      (imm 0x00FF)
ours   :  addiu $v0, $v1, -1        (imm 0xFFFF)

Both are arithmetically identical modulo 256 — only the low byte survives the sb — and both compile to a single addiu, same instruction count, same registers, same schedule. The compiler is not choosing between them on any semantic ground: it takes the immediate from how the literal was SPELLED in the source.

cnt = cnt - 1;        ->  addiu $v0,$v1,-1     (0xFFFF)
cnt = cnt + 0xff;     ->  addiu $v0,$v1,0xFF   (0x00FF)   <- matches

Signedness of the counter (s8 vs u8) was tested and makes no difference; the spelling is the whole lever.

When to reach for it: your diff is a single instruction, the mnemonic and both registers agree, and only the immediate field differs — and the two immediates are congruent modulo the width of the store that consumes the value (sb → mod 256, sh → mod 65536). Then re-spell the literal to the form whose bit-pattern you need. Do NOT reach for pins, scheduling barriers or the permuter: nothing about register allocation or ordering is wrong.

Why it is easy to misread as intrinsic: the residual is one immediate in one instruction, which looks exactly like the tail of a regalloc/scheduling wall. It is not — it is a pure source-text lever, and it is free.

Generalisation to test when it next appears (not yet byte-proven, so treat as a hypothesis): the same should hold for any masked-then-truncated arithmetic where two literals are congruent modulo the consuming store width — e.g. x - 2 vs x + 0xfe, or h - 1 vs h + 0xffff ahead of an sh.

Symptom lines for the index: "only the immediate field differs" · "addiu -1 vs 0xFF" · "one instruction off, same registers".