mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 14:02:04 -04:00
docs(cookbook): §462 — four levers from func_80024054 (74/53/32 -> 4)
From the S76 agent, none previously recorded:
1. array[var-K] folds K into the symbol LO16/lhu displacement, and naming
an intermediate idx does NOT stop it (the fold is front-end/combine,
before any steerable register choice). A zero-byte opacity barrier on
idx, one per use site, is what defeats it.
2. The fused sll 16 / sra 15 sign-extend-scale needs the index declared
s16 — confirms §241's recipe reproduces on a fresh case.
3. A mask-then-compare LOCAL cross-jump-merged two case tails and flipped
branch polarity to bne; switching on the expression directly fixed both
and matched the target's forward-beq. The temporary was the defect —
§461 from the other direction.
4. A pointer parameter's SIGNEDNESS decides how -1 is materialized:
s16* gives addiu -1, u16* gives ori 0xffff, because gcc-2.7.2
canonicalizes the RHS constant against the lvalue's signedness when
picking the load-immediate opcode. Invisible in the C, one instruction
in the asm.
Residual is one permuter-class DELAY-SLOT diff two prior attempts also hit.
This commit is contained in:
@@ -35280,3 +35280,40 @@ drift). The lever is real for one op and a dead end for a chain; do not spend tu
|
||||
**Still open (permuter-class, Law 3):** the `$v0`/`$v1` tie above, and a redundant `D_80073140[i]`
|
||||
re-read the target schedules early to fill a load-delay slot while cc1 schedules it at its use.
|
||||
Every C-level attempt to move it either CSE'd the two reads into one (−1 ins) or added a move (+1).
|
||||
|
||||
#### §462 — FOUR LEVERS FROM `main:func_80024054` (91 ins, 74/53/32 → 4)
|
||||
|
||||
**Source: the S76 agent on `func_80024054`.** Four independent unlocks, none previously recorded;
|
||||
the last one is the kind of rule that silently costs a whole attempt.
|
||||
|
||||
**1. `array[var - K]` folds K into the symbol's LO16 / `lhu` displacement.** Naming an intermediate
|
||||
`idx = var - K` does NOT stop it — the fold happens at the front end / in combine, before any
|
||||
register assignment you could steer. The only thing that defeated it was a zero-byte opacity barrier
|
||||
immediately after computing the index, one per use site:
|
||||
`__asm__ __volatile__("" : "=r"(idx) : "0"(idx));`
|
||||
Reach for this whenever the target loads from `sym+0` with a computed index and your build folds the
|
||||
constant into the displacement instead.
|
||||
|
||||
**2. The fused `sll 16; sra 15` sign-extend-and-scale wants the index declared `s16`, not `s32`.**
|
||||
This confirms §241's recipe on a fresh case — worth knowing it reproduces rather than being a
|
||||
one-off of that function.
|
||||
|
||||
**3. A mask-then-compare LOCAL causes a cross-jump merge AND flips branch polarity.** Writing
|
||||
`bits = val & 0xC000;` then `if (bits == …) else if …` merged two case tails into one shared block
|
||||
and emitted `bne`-polarity branches where the target has `beq`. Dropping the local and switching on
|
||||
the expression directly — `switch (val & 0xC000) { case 0x8000: … case 0xC000: … default: … }` —
|
||||
fixed both at once and reproduced the target's forward-`beq` shape. **The temporary was the defect**;
|
||||
this is the same family as §461's "laundering can be the defect", from the opposite direction.
|
||||
|
||||
**4. 🔴 A POINTER PARAMETER'S SIGNEDNESS DECIDES HOW `-1` IS MATERIALIZED.** Declaring `arg1` as
|
||||
`s16 *` rather than `u16 *` flips the fail-path constant from `ori $x, 0xffff` to `addiu $x, -1`,
|
||||
matching the target — because gcc-2.7.2 canonicalizes the RHS constant against the **lvalue's**
|
||||
signedness before choosing the load-immediate opcode. Nothing about the store's *value* changes, so
|
||||
this is invisible in the C and shows up only as a one-instruction opcode difference. If a residual is
|
||||
a lone `ori 0xffff` vs `addiu -1`, check the signedness of the pointer being written through before
|
||||
touching anything else.
|
||||
|
||||
**Left open:** one `DELAY-SLOT` residual — `addu $a3,$zero,$zero` is insn #0 in the target and lands
|
||||
in the branch delay slot in every C variant. Two independent prior attempts hit the same wall;
|
||||
five further variants (statement reorder, register pin, barriers either side of the load) each left
|
||||
it unchanged or traded it for an equal residual elsewhere. Permuter-class, Law 3.
|
||||
|
||||
Reference in New Issue
Block a user