Files
BFM-decomp/cookbook/C0002.md
T

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.