Files
BFM-decomp/cookbook/C0426.md
T

1.4 KiB

§385 ★★★ — THE SCHED2 PRIORITY-DONOR ASM: closing the "hoisted-invariant vs IV-init preheader swap" class (P31 S69; byte-proven main/func_80038A58, 347 ins, fable escalation 2 → 0)

Closes cookbook §5's open class. Symptom: two independent one-instruction inits after a mult (or any latency chain) emit in swapped order, and the swap is invariant under source order, register pins, and zero-byte barriers.

Root cause, read out of the pinned compiler (sched.c priority():1425 + rank_for_schedule():2385): sched2 schedules BACKWARD. The init that writes a register the mult READS carries an anti-dependence that inherits the mult's priority (anti cost clamps to 1, so +cost-1 = +0), while the dependence-free init stays at priority 1. Priority beats the LUID tie-break, so no C-level reordering can flip it.

The fix — donate priority to the loser via a NON-volatile single-instruction asm with a dead extra input reading the winner's destination:

c2 = 0;
__asm__("addiu %0,%1,18" : "=r"(ptr) : "r"(base), "r"(c2));

The true dep on the c2 init donates priority 2 AND delays the asm's backward release until the donor is placed — target order, identical bytes.

Two traps. A volatile asm cannot be used: volatile is a full scheduling barrier, so it inherits the whole chain's priority and glues itself behind the mflo. And a bare ghost asm whose output is immediately overwritten gets deleted.