Files
BFM-decomp/cookbook/C0231.md
T

2.2 KiB

§210 — THE SINGLE-BIT MASK IN A BOOLEAN TAIL: andi K ; sltu $zero,v vs srl n ; andi 1 is a STATEMENT-SHAPE dial, not an operator choice (P31 S58)

THE TARGET SHAPE — byte-identical tails, two different overlays, found independently by two different drafting agents:

jal   func_80133784
 sh   $v0, 0x1A($sp)
andi  $v0, $v0, 0x2000
lw    $ra, 0x20($sp)
sltu  $v0, $zero, $v0     <- the generic normalisation
jr    $ra

(✔ byte-checked: asm/ov_SC03_029/.../func_8018723C.s and asm/ov_SC03_006/.../func_80188C18.s — the two tails are word-for-word identical.)

THE TRAP. In a straight-line value tail with no join and no branches, the fused expression

return (func_80133784(1, pa, pb) & 0x2000) != 0;     /* WRONG BYTES */

lets gcc see the single-bit mask inside the comparison and emit the bit-extract form srl $v0,$v0,13 ; andi $v0,$v0,1. Refuted on the same card: the ternary ? 1 : 0 and the u32-cast spelling do not fix it.

TWO FIXES, BOTH BYTE-PROVEN, ON THE SAME SHAPE:

card fix result
func_8018723C (ov_SC03_029, wave ag) name the masked value: r = call() & 0x2000; return r != 0; — the statement boundary hides the mask from the != 0 expander MATCH 30/30
func_80188C18 (ov_SC03_006, wave ae) spell the test as CONTROL FLOW: if (x & 0x2000) return 1; return 0; MATCH

Same predicate, three statement shapes, two different final instruction sequences.

THE LAW. Mask visibility to the truth-expression expander is controlled by statement boundaries alone, with no control flow required. When the target shows andi K ; sltu $zero,v and your draft shows srl n ; andi 1, split the mask out of the comparison — either into a named local or into an if.

BOUNDARY. This is a SINGLE-BIT-mask law. A multi-bit mask has no bit to extract and already normalises to andi+sltu from the fused spelling, so the split is inert there. It is also distinct from §164-56/§165-22 (fold_truthop paths over two comparisons) and from §19x/§167-09 (a 0/1 materialised at a JOIN label, which is about naming a condition, not a mask) — those cannot fire on one mask of one call result. §195-E's value-vs-no-value axis gains this as a third dial.