1.7 KiB
§1 Idiom catalog (asm pattern → C that produces it)
I1 — Unsigned range check: (x - lo) < (hi-lo) → addiu+sltiu
Target: addiu v0,v1,-0x51 ; sltiu v0,v0,0x5f (true iff x in [0x51, 0xaf]).
C: if ((u32)(x - 0x51) < 0x5f). The subtract-then-unsigned-compare is the canonical
single-branch range test. sltiu (immediate) is emitted for < constant.
Example: func_80018F20.
I2 — Byte mask forces andi even after lbu
Target: a redundant-looking andi v1,v1,0xff on a value already loaded by lbu.
C: write (x & 0xff) explicitly on the later uses of a byte value (gcc 2.7.2 -O2 does
NOT prove the upper bits zero across pseudo-registers, so the & 0xff survives as andi).
If you omit it, you lose the andi and the diff won't close.
Example: func_80018F20 (first compare uses raw x, the 2nd/3rd use x & 0xff).
I3 — Division by a constant → magic multiply
Target: lui a3,0xcccc ; ori a3,a3,0xcccd ; multu a1,a3 ; mfhi t0 ; srl a1,t0,3 = a1 / 10.
C: just write x / 10 (constant divisor). gcc emits the reciprocal-multiply (0xCCCCCCCD,
shift 3 for ÷10). The magic constant is loop-invariant and gets hoisted to the preheader.
Example: func_80015A74.
I4 — Runtime (variable) division → divu + zero-check break (NEEDS --expand-div)
Target: divu zero,a0,a1 ; bnez a1,.+12 ; nop ; break 0x7 ; mflo <q> ; mfhi <r>.
C: x / y and x % y on the same operands → one divu, mflo=quotient, mfhi=remainder.
Critical: maspsx must run with --expand-div or it emits a bare divu with no zero-check
and the function can never match. This is PINNED in the Makefile (MASPSX_FLAGS).
Example: func_80015A74.