mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 05:56:00 -04:00
067f25f682
Those two objects were originally assembled in REORDER mode (the assembler filled
the delay slots). maspsx force-emits `.set noreorder`, making that unreachable, so
a whole class there read as a permanent compiler wall (§332) when the property
belongs to the OBJECT, not the toolchain.
For REORDER_TUS only, swap maspsx for tools/reorder_passthrough.py + `as -O2` --
the pipeline tools/oracle_reorder.py already proved byte-exact (0 diffs on
func_80061FA8 where the pinned path gives 57). Everything else is untouched.
Verified:
* branch selection BOTH ways: 800c3 -> reorder_passthrough, 800.c -> maspsx
* tools/reorder_passthrough.py --selftest, incl. a negative control (a line
merely CONTAINING "move", e.g. `jal remove_thing`, must not be rewritten)
* BYTE-INERT: main rebuilds BYTE-IDENTICAL via verify_binary (§384, re-extracts)
Note the first patch used `ifeq ($(filter $*,...))`, which make evaluates at PARSE
time when $* is empty -- it would have silently always taken the maspsx branch.
`$(if ...)` expands per-target, which is why the rule already uses that form for
JTBL_PADS.
47 lines
2.4 KiB
Python
47 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""reorder_passthrough.py — the §332b assembler-REORDER path, for the objects that were built that way.
|
|
|
|
THE PINNED PATH is `cc1 -> maspsx -> as -O1`, and maspsx force-emits `.set noreorder` after every
|
|
`.ent`. That is correct for the whole fleet EXCEPT the `800c2` / `800c3` PsyQ island, whose ORIGINAL
|
|
objects were assembled in REORDER mode: the assembler itself filled delay slots. `as` cannot be asked
|
|
to do that once `.set noreorder` is in the stream, so a whole class of functions there looked like a
|
|
permanent compiler wall (§332) when it is really a per-OBJECT assembler MODE.
|
|
|
|
This filter is the maspsx replacement for those objects, and it does exactly what the proven oracle
|
|
(`tools/oracle_reorder.py`, measured 0 diffs on func_80061FA8 where the pinned path gave 57) does:
|
|
take cc1's output and rewrite `move` into the `addu rd, rs, $0` form, leaving `.set noreorder` absent
|
|
so `as -O2` performs the original reorder-mode slot filling.
|
|
|
|
WHY NOT MASPSX WITH A FLAG: maspsx's other transforms (div expansion, li expansion, macro handling)
|
|
are not needed by these two objects — §332b measured the swap BYTE-INERT across the whole of both —
|
|
and adding a mode to a pinned submodule to serve two objects is the larger, less reversible change.
|
|
|
|
cc1 ... | python3 tools/reorder_passthrough.py | as -O2 ...
|
|
|
|
The whole-binary byte gate remains the sole arbiter (G3/P9): if this were wrong for any object it is
|
|
built into, main's SHA1 changes and the build fails.
|
|
"""
|
|
import re
|
|
import sys
|
|
|
|
# `move $a, $b` -> `addu $a, $b, $0`. gcc-2.7.2 emits the macro; the original objects carry the
|
|
# expanded form. Identical semantics, and it is what oracle_reorder.py proved byte-exact.
|
|
_MOVE = re.compile(r"\tmove\t(\$\w+),(\$\w+)")
|
|
|
|
|
|
def convert(text):
|
|
return _MOVE.sub(lambda m: "\taddu\t%s,%s,$0" % (m.group(1), m.group(2)), text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if "--selftest" in sys.argv:
|
|
got = convert("\tmove\t$v0,$a0\n\tnop\n\tmove\t$s1,$zero\n")
|
|
want = "\taddu\t$v0,$a0,$0\n\tnop\n\taddu\t$s1,$zero,$0\n"
|
|
ok = got == want
|
|
# negative control: a line that merely CONTAINS "move" must be untouched
|
|
neg = convert("\tjal\tremove_thing\n")
|
|
ok &= neg == "\tjal\tremove_thing\n"
|
|
print("reorder_passthrough selftest:", "OK" if ok else "FAILED")
|
|
sys.exit(0 if ok else 1)
|
|
sys.stdout.write(convert(sys.stdin.read()))
|