Stubs 32 -> 31 after the func_80015760 bank (commit:3877); R22 fleet 213/213 (.run/S79_check_all_8.log);
main game-code 93.5% (38,854 / 41,534). Permuter ILS plateaus recorded with their residual named:
func_80015608 best 1, func_80039B20 best 7, func_80038698 pinned seed refused (11). The ILS runner
had reported "no waypoint" for 8 cycles in 20 s on a seed the permuter's C parser rejects; it now
prints [permuter] REFUSED and leaves PERMUTER_REFUSED.txt (positive-controlled on func_80038698).
Stubs 35 -> 32 after the #7 banks (commit:3873 commit:3874); R22 fleet 213/213 (.run/S79_check_all_7.log).
ov_SC05_018:func_80180BE0 and ov_SC06_010:func_801809E4 have NO draft: their ledger drafts were other
overlays' same-named functions (.run/backlog_drafts/<fn>.c is keyed by bare fn name) -> drafting pool.
config/wave_exclude.txt: main:func_80011380 pinned WALL with the §474 proof (fold-const split_tree +
stupid.c adjacency), 4 entries.
Stubs 38 -> 35 after the #6 banks (commit:3868 commit:3869 commit:3870 commit:3871); R22 fleet 213/213
(.run/S79_check_all_6.log); frontier_classify 35 rows (main 16, md_MAIN_003 5, resident 2, ov 12).
jtbl_pads_fix's PAD_ERR_MORE regex carried jtbl_rodata_pads' old wording and reported "no
pad-count drift" over a red build; it now accepts both spellings and, positive-controlled with a
deliberately short spec, reports "emits >4 table(s), spec declares 4". The deferred carves and
their blockers are itemised in §491 and in the checkpoint's task #7 brief.
Both gated in parallel worktrees (parallel_gate, pinned at commit:3870) and rebuilt in-tree
byte-identical: ov_SC04_018 fe9b413f (after `make extract` — the merge changed the yaml carve
rows tail18-20 and the JTBL_PADS spec, and the main tree's split was stale until re-extracted),
ov_SC05_005 452897fc. The ov_SC05_005 remap needed two plumbing fixes: the TU's stale
`extern void` prototype (committed byte-neutral in commit:3870) and the draft's duplicate
Prim_8016E7C8 typedef (identical to the TU's, still a redeclaration for gcc 2.7.2).
800c3 (0x8005CE18-0x8005FC68, one contiguous run of 33 interleaved Sony objects) is now four
stub rows — libapi1 (21 BIOS trampolines + COUNTER), libpad1 (PADENTRY + PADMAIN 760), libapi2
(L02/L03), libpad2 (PADCMD PADIF PADPORTD PADSEQD WAITRC2) — fed by two WINDOWED psyq_integrate
calls from the raw .run/obj42/{libapi42,libpad421} dirs (integrate tiles each stub with one
library; every boundary checked against .text SECTION sizes). The apicard region's three
"game code" rows were libapi 4.2's C objects to the byte: 800c2 = FIRST.o (firstfile + the
"no jump table wall" stub func_80062144), 800c2_2 = PAD.o, 800c2_3 = PATCH.o + CHCLRPAD.o ->
apicard5/6/7; make_apicard_used.py sources libapi from 4.2 (the EXE's real libapi; libcard
stays 4.0) into .run/obj42/apicard_used, 26 objects / 7 blocks, no game code left in
0x80061F38-0x80062888. src/800c3.c (129 hand-matched "C", 62 verbatim bodies, 19 stubs incl.
the four §332 %lo-in-a-delay-slot "walls"), src/800c2.c, src/800c2_2.c, src/800c2_3.c removed;
REORDER_TUS is empty (mechanism kept). Cookbook §490.
Two stale instruments fixed: exclude_audit let a pinned WALL outrank LINKED (PopMatrix/
PushMatrix had sat as walls since S68 while living in libgte3, linked since Phase 8) — LINKED
dominates now, config/wave_exclude.txt 13 -> 3; frontier_classify carried a hard-coded 49-name
LINKED set (R51) and reported 337 "stubs" — derived from the Makefile now.
Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH all SDK dirs and WITHOUT them from
a fresh extract; make tools-health OK; R22 fleet extract-all 212/212 + check-all 213/213.
Metrics: main REAL 839->773, LINKED 1,150->1,256, VERBATIM 29->3, stubs 29->16, byte-identical
2,075/2,091 = 99.2%; game-code weighted 93.3% (38,748/41,534), remainder 2,786 = the open-stub
sum; fleet stubs 51->38 (frontier_classify: 39 rows incl. the data word). Verbatim manifest
33 -> 6. Docs: worklist rows + "S79 task #5", SETUP (fresh-clone obj42 commands, Makefile
blocks, exclude_audit), decision-log "S79 addendum 2", accelerators "S79 (2)", CURRENT_PHASE
S79 FINAL refreshed (census, metrics, the task #6 brief).
The bounded hunt succeeded on its first lead. archive.org item
`play-station-programmer-tool-runtime-library-version-4.2.7z` (383 KB) is the PsyQ Runtime
Library 4.2 (LIB/*.LIB + INCLUDE, 1998-01-21) plus LIB/42PATCH/J421PD.ZIP — SCE R&D's
1998-02-26 "Libpad.lib version 4.2.1 for the Analog Controller (DUAL SHOCK)" patch, shipping
LIBPAD.LIB 4.2.1 with LIBAPI.LIB 4.2 and LIBPAD.H/LIBAPI.H/KERNEL.H.
Placed and byte-verified against the EXE (psyq_identify 0x8005CE18-0x800629DC, then
psyq_link.py per object): libpad 4.2.1 7/11 — PADENTRY, PADMAIN (760 ins, the 4.2.1 build,
exact), PADCMD, PADIF, PADPORTD, PADSEQD, WAITRC2 — and libapi 4.2 39/88 — the 21 band
trampolines, COUNTER, L02/L03, and the apicard-region C112/A50/A51/A54/A65/A67/A69/FIRST/A66/
PAD/A18-21/PATCH/CHCLRPAD. All 46 PASS. Neighbours for the record: plain libpad 4.2 and the
4.3 disc (DTL-S2340, 1998-05-18; PADMAIN 832 / PADIF 380 / PADSEQD 292) each place only 4;
4.2.1 is the unique exact match, so the game was built between Feb and May 1998.
Banked (R20): the 7z tracked under tools/psyq/ with sha256 + provenance in CHECKSUMS.sha256;
extracted to gitignored tools/psyq/lib42/ and lib421/ (the 4.2.1 headers are the band's
prototype oracle from now on); ELF in .run/obj42/{libpad421,libapi42}. Docs: psyq-worklist
"S79 task #13", SETUP archive table + §5.1 + S79 tool table, CURRENT_PHASE (#13 log; the S79
FINAL block's §5 records the archive and §6 is the re-scoped task #5 brief: link the whole
0x8005CE18-0x8005FC68 band and re-source the apicard region's libapi from 4.2).
The §9.1 "scattered .bss commons" exclusion class (Phase 8 → P31) is closed 3/3. New
tools/psyq_bss_split.py (own ELF32 REL reader/writer) cuts an object's packed .bss into
per-base NOBITS pieces: bases derived from the game bytes per HI16/LO16 pair, references
walked in offset order into single-base runs, cuts snapped to symbol starts (the linker
scattered SYMBOLS), symbols moved, a LOCAL section symbol per piece inserted, relocs
retargeted with the addend rewritten in the immediates, self-diffed. It runs inside the one
prepare step shared by psyq_link.link_object / psyq_link_region.build_region /
psyq_integrate.integrate (prepare_object before classify), re-derived every build.
GS_001.o was certified "5 interleaved bases, NOT splittable" by the S77 probe, which grouped
by BASE; by RUN it is six symbol-aligned pieces. All seven cuts across the three objects are
confirmed by the other objects' by-name recoveries (_que 0x800C5510, _svm_sreg_buf
0x800B9B58, PSDBASEX/CLIP2/PSDBASEY/POSITION/GsDRAWENV). R39 negative control: 235 placed
objects across 9 curated dirs, 0 refusals, exactly 3 splits (a libcd .bss+size end pointer
refused the first build → reference problems are fatal only when a split is needed).
Wiring: yaml 800c→libgpu2, sgap_6→sgap_6+snd12, gsgap3→libgs8 (comments rewritten);
LIBGPU_ELF := .run/obj40/libgpu (curated libgpu_used retired); libgs 34 objs/8 blocks
(make_libgs.sh +GS_001); snd 63/12 (make_snd_used.py exclusions 4→3). src/800c.c and
src/gsgap3.c removed (Sony code hand-matched as REAL/verbatim), sgap_6.c keeps only
func_8003FA54; splat-emitted libgpu2.c/libgs8.c/snd12.c stubs for the no-SDK fallback.
Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH the SDK objects and WITHOUT
them from a fresh extract; make tools-health OK; R22 fleet clean extract-all 212/212 +
check-all 213/213. Metrics: main REAL 886→839, LINKED 1,040→1,150, VERBATIM 85→29, stubs 29
(unchanged); game-code weighted 91.1% (40,895/44,870) — both terms lost the 3,667 SDK ins;
the remainder is still exactly the 3,975-ins open-stub sum. Verbatim manifest --update
200→33 rows (subtractive). Docs: cookbook §489 (+index), psyq-worklist rows + "S78 task #4",
SETUP S79 R21 table, decision-log S79 addendum, accelerators S79, CURRENT_PHASE S79 FINAL 🛑.
- exact tiles, 0 tokens: libgte23-26 (MSC01/02/05/09, SMP_00, FGO_01-06, PATCHGTE), libgte9 re-derived
as SMP_05 NormalClip (SMP_06 NormalClipS = nested sub-pattern; psyq_integrate now drops nested
placements), libgte27-30 (the libgs-gap MTX_05/07/11, REG03+REG11), libgs7 (2D_BG0+2D_BG1), snd10
(VM_NO1), snd11 (VM_NOWON carved off sgap_8). LINKED 959->1040, REAL 912->886 (SDK inline-asm wrappers
re-provenanced), VERBATIM 146->85, 13 TUs deleted; splat re-emits the stub records.
- main 143dbb89 WITH and WITHOUT the SDK objects. The no-SDK fallback had been red since S7x
(CdReadyCallback called by its SDK name while the libcd stub carried func_800435B4) — curated
CdReadyCallback = 0x800435B4, refs unified. R22 clean fleet 213/213; tools-health OK.
- METRIC CORRECTION (R35): progress.py's "MAIN game-code weighted" sig never excluded the LINKED
objects (its comment said it did) — ~31k linked-SDK ins sat in the denominator as unmatched game
code. Exclusion now derived LIVE from the Makefile stub lists + yaml ranges: 91.8% (44,562/48,537),
not 59.8%; the 3,975-ins remainder equals the open-stub sum exactly.
- VM_F.o probed SPLITTABLE at .bss 0x50c (SYS.o's class -> task #4). cookbook §488; worklist S78 #3;
decision-log + accelerators; SETUP rows.
- provenance: the psx loader's per-version PsyQ signature sets place PADENTRY/PADCMD/PADPORTD/
PADSEQD (4.2), WAITRC2 (4.3), COUNTER/C114/FIRST/PAD/PATCH/CHCLRPAD (libapi 4.2) byte-exact in
0x8005CE48-0x8005FC68 / 800c2 -> 12 of main's 29 stubs incl. all four §332 walls are Sony's
DualShock library in reorder mode. 46 names -> symbols.us.txt (count 1081), band TUs, verbatim
manifest, wave_exclude; firstfile/firstfile2 (4.2 naming); CdGetToc @0x800430B8 (was the Phase-21
xdedup mislabel DecDCToutCallback). SETUP §5.1 corrected; psyq-worklist S78; cookbook §487;
decision-log + accelerators S78; CHECKSUMS +Psy-Q_46.zip +PSYQ_SDevTC_v4.5.zip.
- psyq_integrate: --yaml maps stub<->objects by SUBSEG RANGE with an exact-tiling check and PRINTS
the located-but-unwired residue (libgte: 13 objs / 1,264 ins) — main's LINKED build had been RED
at HEAD since the S77 psyq_identify fix (22 libgte blocks merged to 3; gate worktrees take the
stub fallback so it never showed); a library object's exported symbol whose recovered address the
curated file names differently is --redefine-sym'd (R15; A66 firstfile->firstfile2).
- Ghidra: 47 MCP renames did NOT persist through the sentinel stop (R9 caught it) -> NEW
tools/ghidra_scripts/ApplySymbols.java + tools/ghidra_apply_symbols.sh mirror the curated file
headless with a real save: 73 renamed, R9-verified x4. SETUP inventory rows (R21).
- lint_symbol_refs: scans verbatim __asm__ bodies (`.ent\tfunc_X` is invisible to \b and to the
string-masked scan); negative-controlled (red on the pre-fix TUs, green on the passing tree).
- R22: clean extract-all 212/212 + check-all green on the final config; main rebuilt byte-identical
143dbb89 after the last src-only fix -> 213/213; tools-health OK.
The fleet report still printed 'caveat is R34: no independent second oracle for
a PS-X EXE'. That was true until this session; make sig-main-oracle +
audit-corpus now cover main at 0 phantom / 0 truncated / 1 explained pad-tail.
A stale caveat is the same class of false statement as a stale wall verdict.
obj_text_pattern parsed ONE WORD PER DISASSEMBLY LINE, and objdump collapses a
run of identical words into a single `...` line. Every collapsed word was
silently missing from the pattern, so from the first run onward the pattern was
MISALIGNED against the image and find() returned None -- printed as the
confident, wrong sentence "not linked by EXE".
Measured on 2D_BG0.o (libgs): 3 `...` lines, 520 words parsed for a 526-word
object. It was listed as absent while 507 of its 507 non-relocated words match
the EXE exactly at 0x8005080C. Any object whose .text holds a run of >=3
identical words was invisible -- to the map the entire library-linking pipeline
consumes for placement.
That is why 2D_BG0.o was never linked: not excluded by a reason, just invisible.
It sits in config/splat.us.exe.yaml under a scattered-.bss exclusion that cannot
apply to it, since the object has no .bss section at all.
Reading the section bytes and taking relocation offsets from `objdump -r`
removes the pretty-printer from the loop (R33).
MEASURED: libgs goes from 36/201 to 46/201 objects located.
The 3-way split moved func_8002FDE8 and func_80032A74 into the 800_b_2 subseg,
but their INCLUDE_ASM directives still named "asm/nonmatchings/800_b". The
incremental build passed anyway because the OLD .s files were still on disk;
make clean removed them and splat now emits under 800_b_2, so a genuinely clean
rebuild died in jtbl_rodata_pads:
FileNotFoundError: asm/nonmatchings/800_b/func_8002FDE8.s
This is exactly what R22 exists to catch, and it is the reason a byte check is
only trustworthy from a clean tree. asm/nonmatchings/800_b no longer exists at
all -- piece 1's three functions are all banked, so splat emits no directory
for it.
main rebuilds 143dbb89f34491258bbc27810d0a12ec8b43a8dd from a clean extract.
The body was MATCH 299/299 from the S77w wave and could not bank for want of an
-O0 object. With the 3-way carve in place it gated first try.
gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
func_8002C410 MATCHES 299/299 at -O0 and DIFFs 228-vs-299 at -O2 (verified
independently with match_one --o0 vs --no-auto-o0). gcc-2.7.2 has no
per-function optimize pragma, so opt level is per FILE, and the function needs
its own object. Main had no path to one: the Makefile's -O0 wildcard covered
src/ov_*/ and src/md_*/ but NOT top-level src/*.c, and o0_subsplit.py is
overlay-shaped -- it died on config/splat.main.yaml, which does not exist.
Measured the scope first (R37): the -O0 detector flags exactly TWO open main
stubs -- this one, and func_80011380, which already lives in -O0 boot.c and is
the proved floor. So this unblocks one function, not a class.
FIVE COUPLED PIECES, which is why the carve is worth recording:
1. splat code rows: 800_b cut 3 ways -- 800_b / 800_b_o0a / 800_b_2
2. splat .rodata: span B SPLIT, because the 3-way cut put its two jtbl owners
in different objects -- func_8002B0B4 into 800_b, func_800335B8 into
800_b_2 -- and one code object may contribute exactly ONE contiguous
.rodata run. The boundary is DERIVED, not guessed: 800_b.o's compiled
.rodata is 0xf8 bytes, so the front run ends at 0x80072E44+0xf8. The
build's own jtbl_rodata_pads caught the missing piece.
3. src/800_b.c split 3 ways -- 86-line prologue duplicated, 3 defs before the
island, 97 after
4. Makefile -O0 glob widened to top-level src/*_o0?.c
5. ld_interleave --order: 800_b_2.o inserted after 800_b.o. Missing this
floated the tail rodata and shifted every data symbol by exactly its size,
+0x204, across 704 two-byte runs -- which is how it was found.
o0_subsplit.py now REFUSES main loudly instead of dying on a missing file
(R43/R61a) and names the manual procedure.
VERIFIED BYTE-NEUTRAL BEFORE ANY BANKING: main builds
143dbb89f34491258bbc27810d0a12ec8b43a8dd with the split in place and
func_8002C410 still an INCLUDE_ASM stub.
The yaml has excluded SYS.o/GS_001.o/2D_BG0.o/VM_NO1.o from the LINKED build
since Phase 8 for 'scattered-.bss commons ... no single NOLOAD base reproduces
it'. Every word of that is true, and it does not imply unlinkable.
psyq_bss_probe derives each object's .bss bases FROM THE BYTES (for each
HI16/LO16 pair against the bare .bss section, the object's immediates give the
addend and the game's give the resolved address, so base = resolved - addend)
and then asks the unasked question: are the offset ranges DISJOINT?
SYS.o 3,109 ins 2 bases 0x0000-0x0044 @ 0x80078830
0x0148-0x0150 @ 0x800c53cc -> SPLITTABLE at 0x148
GS_001.o 384 ins 5 bases interleaved -> the genuine wall
2D_BG0.o 526 ins NO .bss -> reason cannot apply
VM_NO1.o 305 ins NO .bss -> reason cannot apply
§9.2's escape (weaken the .bss symbol, --defsym it) really cannot reach these —
a relocation against the bare SECTION has no name to defsym — and that is what
made 'unlinkable' look like the conclusion. But a section reference only needs
the section PLACED, and a section can be split.
Completeness checked before believing it (R32): the probe counts .bss refs from
EVERY section; SYS.o's .data has zero, so the two-way split covers every
reference. Placement is derived, not configured — the object is located by
masking relocated fields and requiring a UNIQUE match, which independently
reproduced SYS.o @ 0x80059234 / 3,109 ins, agreeing with both the yaml subseg
bounds and the manifest's psyq_identify count.
Incidental: src/800c.c is 100% SYS.o (its span is exactly the object's .text
size), despite the subseg comment calling it '-O2 game code'.
Cookbook §484; yaml comment corrected in the same change.
The roadmap's completion contract requires both audit oracles green before any
100% claim on main, and main had none: audit-corpus covered overlays and
resident only, and R34 is explicit that the byte gate is a perfect CORRECTNESS
oracle and a NULL COVERAGE oracle — green whether a function was sliced right
or invented, because the .s pieces paste back either way.
sig_image gains multi-range signing, closing all three blockers
docs/second-oracle.md scoped:
* the 0x800 PS-X EXE header -> --vram-base 0x8000F800 puts file offset 0 at
vram, so the header falls below the first range
* interleaved data + linked islands -> --segments derives 28 game-code ranges
from the splat yaml's SEGMENT rows
* one text range -> the signer loops ranges, bootstrapping INSIDE each, which
is what stops the linear partition running through a data island and minting
functions out of it (the detector manufacturing the class it detects)
INDEPENDENCE IS PRESERVED, NOT WORKED AROUND. Ranges come from segment TYPES,
never from splat's function boundaries; entries are still found by byte-derived
jal-closure. Seeding from splat's symbols would make every phantom look real —
the trap the design doc names. .run/sig.main.jsonl (the splat-SEEDED atlas sig)
is a different file and corpus.ORACLE_SIG keeps the audit off it.
RESULT: 986 functions signed. main audit = 0 PHANTOM, 0 TRUNCATED, 1 PAD-TAIL.
Fleet audit-corpus = 0 + 0, unchanged for resident and overlays.
NEW AUDIT CLASS, from the first real finding. func_80062144: splat .s 65 ins,
oracle 64 — the extra line is a nop one line BELOW endlabel. That is an
alignment pad the matching side already emits from C (§295; two S77 wave agents
did it on func_8005E13C and func_8005D538), not a mis-slice. Lumping it with
TRUNCATED would make the oracle's first finding look like a defect and bury the
class that is one.
COVERAGE ASSERTED both ways before trusting it (R32): all 30 game-code stubs
fall inside a range, and 0 of 199 addr-parseable LINKED stubs do.
tools-health caught this red: seven sections added this session without
regenerating the index. Exactly the sibling-update the health gate exists to
enforce.
THE GAP: a drafting agent is briefed to STOP at a plateaued permuter-class
residual — right, since an agent grinding a register permutation burns tokens
for nothing — so every SCHEDULE-REORDER/DELAY-SLOT/REGALLOC-PERM residual lands
unattempted while the local permuter costs no tokens. In S77 the hand-off
happened only when I remembered.
THE CORRECTION THIS TOOL FORCED. §479 v2 claimed the predictor of a permuter win
was 'prior-attempt history: all 3 winners were drafts nobody had worked'.
Building the selector on that claim refuted it immediately: journal_notes
reports prior attempts for ALL EIGHT known runs, winners included (2, 3, 3).
What I had eyeballed was the DRAFT HEADER narrative, a different corpus — the
winners came from a recovery pile whose files carry no header journal. That is
provenance, not evidence.
So the tool selects on the two NECESSARY conditions only (small residual, a
match_one class the permuter can search), prints prior-attempt counts as
information, and puts the unvalidated filter behind --skip-ground, off by
default so it cannot silently discard good work (R39).
AND A BUG IN THE NEW TOOL, caught by cross-checking against known-true numbers:
wave_results globbed journals across EVERY session and did last-write-wins on a
bare function name, so an older wave's row won and carried its stale
draft_path — the sweep reported func_8002AC98 at closeness 73 and func_80015608
at 65 while both drafts measure 1 and 3. R48 inside a brand-new tool. Journals
are now read newest-last and rows are kept only when the draft lives under this
wave's directory. After the fix all seven cross-checkable residuals agree with
what the agents independently reported (9, 8, 7, 3, 3, 1, 1).
§479 now states the honest position: ~3 in 8 at <=4, no validated predictor, and
a note that a yield table is evidence while a story about why is a hypothesis
needing its own negative control before it goes in the cookbook.
gate_main printed ONE recovery chain for every dropped draft, and it was the
SELF chain (fix_arity_callers --any-proto + cast_self_callers) regardless of
what the clashing symbol actually was. Two of the three classes are not that
chain:
CALLEE — §378 does not transfer; cast_self_callers reads the return type off
the draft and cannot cast a callee, so --any-proto runs unprotected
over every call site. S69 measured 60 decls no-protoed, binary RED.
DATA — neither tool in the printed chain touches a data extern at all.
Measured cost of the wrong route THIS session: func_8006252C was dropped on a
clash with itself; following the shape of the printed chain I reached for
scope_demote_drafts first, which aliased D_80078D08 through __asm__ and BROKE
the build. The real blocker was one --sync-decls away. Three tools, wrong
order, one destructive — because the report named a chain instead of a route.
A route is an ORDERED LADDER, not a prediction: for a DATA clash the choice
between adopting the TU's spelling and demoting to block scope depends on
whether the draft can live with the TU's type, which no classifier can know.
The byte gate remains the sole arbiter (G3/P9). Refusals come first (R43/R61a):
a verbatim draft and a NEAR are not declaration problems.
NEGATIVE CONTROL (R39): all 7 S77 drops whose winning tool was already known
route correctly — 2 SELF (cast_self_callers), 1 CALLEE (sync_tu_decls via a
definition header), 4 DATA — and the DATA ladder's order matches which rung
actually won in each case (sync for D_80072978, demote for D_80072960 and
D_80074818). Verbatim draft refused; real-C draft not refused.
Playbook §4b and SETUP updated in the same change.
The first version of §479, written earlier this session on 3 data points, said
the permuter is a one-shot at <=4 mismatched. Five more runs make it 3 of 8,
and the failures are not marginal: a residual of 1 failed while a residual of 4
banked, so mismatch count predicts nothing.
The real predictor is prior-attempt history. All three winners were drafts
nobody had worked. Every failure was a body an agent or prior wave had already
optimised (5, 6 and 4 prior levers respectively). A draft a competent search has
plateaued is plateaued for the permuter too — its wins come from unexplored
neighbourhoods, not from small numbers.
Same predictor as §479's triage paragraph, reached from the opposite direction.
Five new levers, all in the draft header. The headline one (L5): STATEMENT
ORDER IS THE ALIAS ORDER — a mem/s local matrix store can never be hoisted over
by a mem/s varying p-> load, because true_dependence's exemption needs one side
non-struct AND non-varying. Writing the matrix init in NATURAL OFFSET ORDER
closed the whole 45-instruction init block, and the same law one scope down
removed the +1 length drift.
Also: an inline-asm "r" operand that is a bare symbol_ref has NO pseudo and is
allocated by reload ($t0); assigning it to a local first makes it a pseudo and
local-alloc gives $v0 — worth 10 instructions.
A scripted 858-candidate sweep PROVED mode/rot/shift placement inert, which is
what redirected the hunt from LUID to DAG/allocation.
gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
replace_decl returned True whenever the PATTERN matched, even when the
substitution produced identical text. So a draft that already carries the TU's
exact spelling looped until --rounds ran out, spending ONE CLEAN REBUILD PER
ROUND, and then printed 'gave up after 6 rounds (6 synced)' — which reads as
six useful syncs.
Measured on func_8005FA94: 6 rounds, every one
'D_80072960 -> extern void (*D_80072960)(void *);', zero change to the draft,
five wasted rebuilds and a misleading report. R61(a): a no-op must not be
reported as work.
Two guards: no text change ends the loop naming the already-correct spelling
and saying the residual is elsewhere; and a symbol the gate names twice in one
run ends it too, since re-syncing it cannot help.
The comparison is LINE-NORMALISED because the pattern ends in \s*$ and the
substitution eats the matched line's newline — a byte compare called that a
change. Caught by a known-true check (identical/different/absent), not by
reading the code.
18 -> 0 via three levers, all worth reading in the draft header: the sibling
func_8002FF0C's block-scope scalar spelling of D_800A46D2 (the array spelling
lets cse cache 'la $s1' across the call); splitting a $17 pin so only the
b*24 intermediate is pinned (expand_mult passes accum_target=target, and a HARD
target survives expand's generate-into-pseudos guard, so pinning the result
drags the whole chain); and pinning the DESTINATION for idx98, because
'addu $s0,$s1,$s0' is expand_binop swapping commutative operands to make
op0==target, not tree order.
Gated compatible on the first try — the agent had verified the spliced TU
compiles rc=0 with an instruction stream identical to the standalone compile.
gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
Took three tools in order, and the first two were wrong:
- scope_demote_drafts BROKE it (it aliased D_80078D08 through __asm__ and the
build failed) — the clash was never a data extern
- the real clash was func_8006252C ITSELF: TU void(void) vs draft s32(void),
i.e. self_decl_tu -> cast_self_callers --sync-decls, 4 call sites
- then sync_tu_decls closed func_800625DC and func_80062644
The BODY is the interesting part and is now cookbook §482: two INDEPENDENT asm
re-ties, ordered, because one barrier fixes one residual and re-creates the
other.