Files
BFM-decomp/cookbook/C0243.md
T

3.1 KiB
Raw Blame History

§222 — SWITCH vs IF-CHAIN, PART 3: source arm order IS emission order, a leading EMPTY case buys the median split, and a 2-way dispatch with a shared post-block is a switch (P31 S58)

Composes §206.2 (an empty case owns a table slot), §164-54 and §193-G (the dispatch-topology oracle). Three new decisions, three cards.

1. ARM ORDER IN THE SOURCE IS ARM ORDER IN THE ASM — including a non-ascending case sequence. func_80183A1C (ov_SC06_000, wave af, 65/65): the residual after the twin was case ORDER — case 1: must precede case 0: because case 1's body sits at the first beq's target. And the empty case 2:/case 3: arms are required to synthesise the slti/beqz/bnez range-check prologue. §164-55/§165-12 price arm order for if/return shapes; the dense-switch-with-a-leading- non-zero-case ordering law was unstated.

2. AN EMPTY LEADING case 0: IS WHAT PUTS THE MEDIAN SPLIT IN. func_8017F3B0 (ov_SC02_017, 49 ins): the target has a lone slti $v0,$v1,2 between two beqs — §164-54's dispatch oracle reads that as a switch with a median-split tree. But with cases {1,2} + default, a bare if(v==1)…else if(v==2)… emits bne/li/bne and no slti at all. Writing an empty case 0: makes case 1 the tree's low leaf so emit_case_nodes puts case 1 left of the split and case 2 right — reproducing the target. Two earlier drafts using if/else-if chains gave 45 and 47 ins against 49.

3. A TWO-WAY u16 DISPATCH WHOSE ARMS SHARE A COMMON POST-BLOCK COMPILES AS A switch. func_80181968 (ov_SC04_004, 46/46): the lhu/beqz+beq pair on *(u16*)(a0+0x34) is not if/else-if — gcc emitted a shared tail (addu a0,s0 / two fall-in labels) that only a switch reproduces. The if/else-if chain hoisted the addu into delay slots and dropped the j (−2 ins LENGTH-DRIFT). This sits below §193-G's three-node threshold, so it is a distinct tell: the discriminator is the SHARED POST-BLOCK, not the arm count. (single observation at 2 arms — not yet cross-confirmed)

4. WHEN THE GAPS ARE INTERIOR, DO NOT WRITE THE EMPTY CASES. The counter-instance, and it is §165-28 working exactly as documented: func_8017D740 (ov_SC03_007, 41/41) reconstructs switch((func_800291B4(0xCC)&0xFF)-3) over cases 3..14 from a 12-entry table whose even slots 4/6/8/10/12 hold the epilogue address. Those are interior default-filled gaps with 7 live nodes ≥ CASE_VALUES_THRESHOLD, so no empty case labels are written. Read §206.2 and §165-28 together: an epilogue-pointing slot is an empty case only when §165-28's two-question test says the gap is not interior-and-dense.

5. READ THE JUMP TABLE FIRST — it settles the case structure with zero compiles. func_80180204 (ov_SC03_031, wave af, 56 ins, MATCH first draft): with the twin at ~0.59, the whole structure fell out of jtbl_801C4B60's entry list plus the two merge points — .L8018029C as a store-tail and an absent default (out-of-range falls straight past the switch). The table even carries a 6th pad word (0x01222211) that is never addressed, per §8e.