mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-05 08:57:59 -04:00
1.8 KiB
1.8 KiB
§339 — A 2-CASE SWITCH OMITS THE LOW-BOUND RANGE TEST, SO THE PRESENCE OF slti/bnez BETWEEN THE beqs IS A COUNT TELL FOR A THIRD CASE NODE (P31 S67; byte-proven ov_SC02_005/func_80190538, 197 ins)
stmt.c's emit_case_nodes carries the rule in its own comment — "omit the conditional branch to
default if we avoid only one right child" — so a switch with TWO case nodes emits no low-bound
check, while THREE emits one. That makes the range test a structural count you can read off the
target, not a detail to reproduce by luck:
beq $v1, 1, ... <- case 1
slti $v0, $v1, 2 <- THIS PAIR ONLY EXISTS IF THERE ARE >=3 CASE NODES
bnez $v0, default
beq $v1, 2, ... <- case 2
Seeing slti/bnez sitting BETWEEN two beqs means a case node is missing from your draft. Adding
case 0: return; supplied exactly the missing 2 instructions here. Read the case count off the
range test before you start rewriting arms.
Three more dials byte-proven on the same function, all reusable:
- A frame's "holes" can be struct padding, not scalars. Slots 0x20/0x24/0x28 + 0x30/0x38 with
gaps at 0x2C/0x34/0x3C are TWO 16-byte VECTOR-shaped structs whose
padmembers are the holes — not five independent scalars. Cf. §333: frame arithmetic is evidence about DECLARATIONS. A - (B + C)tree-folds to(A - C) - B, which flips anaddiusign. An explicit temp forB + Cblocks the fold.- Declaring temps INSIDE each if-arm instead of at function scope is a REGISTER dial. A
function-scope pseudo spans both arms (ptr=$a2 / dx=$a1 / dz=$a0); block-scope gives the target's
ptr=$a1, first-computed=$a0, second=$v1. Paired lever: putting
v.vy = 0;at the END of each arm rather than after the join keeps the join block'slw $a2,0x24($sp)a REAL load instead of letting cse turn it intomove $a2,$zero.