mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 06:49:47 -04:00
186a8b1548
REORDER_TUS := 800c2 800c2_2 800c2_3 800c3 are piped through reorder_passthrough.py into as -O2 by the Makefile — the mode that fills delay slots and emits the jr/addiu epilogue. That island landed 2026-09-01 and banked 20 functions. match_one, the oracle every drafting agent scores against, still compiled those TUs through maspsx + as -O1, so it reported a phantom LENGTH-DRIFT in the epilogue and an extra instruction. Measured on one plain-C draft of func_8005ECC0: maspsx + as -O1 closeness 5, 36 ins vs 35 'the §188 wall' reorder + as -O2 closeness 2, 35 ins vs 35 epilogue identical Cost, in the S76w wave alone: seven of eleven main agents produced correct C, saw the phantom tail, correctly identified the §182/§188 shape, consulted oracle_reorder.py — which told them 'file IMMOVABLE, no C-level work can ever close it' — and each submitted a §265 verbatim-asm body instead. They all reasoned correctly from a false premise the knowledge base gave them. The TU list is DERIVED from the Makefile, never a second copy (R51 — a derived property stored as config goes stale, which is this defect exactly). oracle_reorder.py's docstring is corrected and the cookbook carries the §182/§188 correction with the byte evidence.
60 lines
4.1 KiB
Python
60 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""oracle_reorder.py — decide whether a NEAR residual is a C defect or an ASSEMBLER artifact.
|
|
|
|
WHY (P31 S53, cookbook §188). The `jr $ra` + `addiu $sp` epilogue tail — and unfilled branch delay
|
|
slots generally — are produced by GNU `as` at `-O2`, NOT by cc1. The project pins `ASFLAGS -O1`
|
|
(Makefile:563) and maspsx force-emits `.set noreorder` after every `.ent`
|
|
(tools/maspsx/maspsx/__init__.py:856-859), so under the pinned triple that shape is UNREACHABLE from
|
|
any C source. A draft can therefore be perfectly correct and still sit at a stubborn residual.
|
|
|
|
THE DIAGNOSTIC: re-assemble the SAME draft two ways and compare.
|
|
maspsx + as -O1 (the pinned path) -> the residual you already see
|
|
bypass + as -O2 (maspsx skipped) -> if this is 0 diffs, THE C IS ALREADY RIGHT
|
|
A 0 in the second cell means the C IS ALREADY RIGHT under a reorder-mode assembler.
|
|
|
|
*** CORRECTED P31 S76 — READ THIS BEFORE CONCLUDING "WALL". ***
|
|
This file used to end that sentence with "file IMMOVABLE, stop grinding, no C-level work can ever
|
|
close it", and the header above still says the shape is "UNREACHABLE from any C source". That was
|
|
true when it was written and is now FALSE FOR FOUR TUs. On 2026-09-01 the build gained a reorder
|
|
island: `REORDER_TUS := 800c2 800c2_2 800c2_3 800c3` in the Makefile pipes those TUs through
|
|
`tools/reorder_passthrough.py` into `as -O2` (ASFLAGS_REORDER) instead of maspsx + `as -O1`. For a
|
|
function in one of them, a 0 here does NOT mean immovable — it means THE DRAFT WILL BANK, because
|
|
the second cell IS the project's real build path for that file.
|
|
|
|
Measured S76: seven main drafting agents in one wave hit the epilogue residual, ran this oracle,
|
|
read the old wording, and each submitted a §265 verbatim-asm body instead of the plain C the build
|
|
would have accepted. `match_one` now selects the reorder path automatically for those TUs (deriving
|
|
the list from the Makefile), so the phantom residual no longer appears. Same draft, func_8005ECC0:
|
|
closeness 5 / 36 ins under maspsx, closeness 2 / 35 ins under reorder — the whole epilogue drift was
|
|
the oracle, not the compiler.
|
|
Measured on func_80061FA8 (target 103 ins): pinned 57 diffs/106 ins; bypass+-O2 0 diffs/103 ins.
|
|
|
|
Promoted verbatim from .run/wave_p31r/oracle61.py because a cookbook section may not cite evidence
|
|
that lives under a gitignored path (the verifier that found this flagged exactly that).
|
|
"""
|
|
"""Byte-exact oracle for the 0x8005D000-0x80062600 PsyQ island: cpp -> cc1 -> (move->addu) -> as -O2.
|
|
Reproduces the ORIGINAL assembler's reorder-mode delay-slot swapping, which maspsx (forced
|
|
`.set noreorder`) + the pinned `as -O1` cannot emit. Diagnostic only -- NOT the project gate."""
|
|
import subprocess,sys,re,os
|
|
sys.path.insert(0,'tools'); import masked_diff
|
|
CPP='mipsel-linux-gnu-cpp'; CC1='tools/bin/gcc-2.7.2-psx/cc1'; AS='mipsel-linux-gnu-as'
|
|
CPPFLAGS='-lang-c -Iinclude -undef -Wall -fno-builtin -Dmips -D__GNUC__=2 -D__OPTIMIZE__ -Dpsx -D_PSYQ -D_MIPSEL -D_LANGUAGE_C'.split()
|
|
CC1FLAGS='-quiet -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker'.split()
|
|
ASFLAGS='-Iinclude -march=r3000 -mtune=r3000 -no-pad-sections -O2 -G0'.split()
|
|
cfile,fn,sub=sys.argv[1],sys.argv[2],sys.argv[3]
|
|
wd='.run/match/oracle61'; os.makedirs(wd,exist_ok=True)
|
|
s=masked_diff.strip_scalar_typedefs(open(cfile).read())
|
|
if '#include "common.h"' not in s: s='#include "common.h"\n'+s
|
|
open(wd+'/t.c','w').write(s)
|
|
p=subprocess.run([CPP]+CPPFLAGS+[wd+'/t.c'],capture_output=True)
|
|
assert not p.returncode,p.stderr.decode()[-1500:]
|
|
q=subprocess.run([CC1]+CC1FLAGS,input=p.stdout,capture_output=True)
|
|
assert not q.returncode,q.stderr.decode()[-2500:]
|
|
asm=re.sub(r'\tmove\t(\$\w+),(\$\w+)', lambda m:'\taddu\t%s,%s,$0'%(m.group(1),m.group(2)), q.stdout.decode())
|
|
r=subprocess.run([AS]+ASFLAGS+['-o',wd+'/t.o'],input=asm.encode(),capture_output=True)
|
|
assert not r.returncode,r.stderr.decode()[-1500:]
|
|
mine=masked_diff.insns_from_object(wd+'/t.o',fn); tgt=masked_diff.insns_from_s('%s/%s.s'%(sub,fn))
|
|
d=masked_diff.structured_diff(mine,tgt)
|
|
print('ORACLE %s mine=%d tgt=%d diffs=%d'%(fn,len(mine),len(tgt),len(d)))
|
|
for i,m,t in d[:15]: print(' ',i,m,'|',t)
|