567b069495
Worker C found that the project's cc1 cannot build a whole class of the original's functions,
and the census is triply verified (C, worker D, coordinator):
623/623 REGISTERED regions contain EXACTLY ONE `jr $31`. ZERO contain two or more.
12 of the 193 NEGATIVES rows contain two or more. That is the entire blocked class.
NOT a flag: 14 flag sets on the default cc1 all yield one exit.
And it produces bodies: 0x800FF43C / 0x800FF47C / 0x80108578 are byte-exact with
gcc-2.8.1-psx/cc1 where the default gives 56/60/52 B LENGTH-MISMATCH.
THE RESTRICTION IS ENFORCED HERE, NOT LEFT TO A CONVENTION. Allowing a second compiler
BINARY widens the corpus, and the project's rule against per-function compiler choice exists
because the gate CANNOT catch a wrong choice -- byte-exact is byte-exact. So a region naming
`cc1bin` is REFUSED unless its original body has >= 2 function-exit jumps, i.e. unless it has
a NAMED MECHANISM in the bytes:
region 0x8006B5F0..0x8006B66C names cc1bin=gcc-2.8.1-psx but its original body has only
1 function-exit jump(s) (`jr $31`); 2 are required. -> exit 2
`cc1bin` takes a BARE vendored directory name under tools/old-gcc/ (no slashes, no paths), so
the nameable set is exactly the pinned set already in the repo. Validated by `sf3_merge` at
merge time and enforced by `sf3_match` before anything is compiled.
THE MECHANISM SENTENCE IN THIS FILE WAS WRONG AND IS CORRECTED, NOT DELETED. My first version
said "2.7.2 emits one shared return epilogue while 2.8.x emits one per return". C's 4-return
probe reproduces that and I reproduced C's probe exactly -- but worker D could NOT reproduce
it: on both a 3-return framed probe and a 3-return frameless probe, ALL TEN builds emitted one
shared exit. Both probes are real, so the compiler-side result is SHAPE-DEPENDENT and the
general claim is false. The census and the three bodies justify the lever; the mechanism was a
hypothesis I recorded as a finding. Left in place, marked as corrected, because the next reader
will otherwise re-derive it and believe it.
ALSO IN THIS COMMIT:
* **The 2.8.x gp access pair.** 2.8.x addresses a global as `lui $R,%hi(SYM)` +
`<op> $r,%lo(SYM)($R)` where 2.7.2 emits a bare `sw $2,SYM`. Both lines were invisible to
the existing regexes, so a gp-touching region built with an alt cc1 came out 4 BYTES LONG.
Now rewritten as a pair: the access becomes `%gp_rel(SYM)($gp)` and the `%hi` is dropped.
My first two attempts at this were both wrong and both are recorded in the code:
it required the two lines to be ADJACENT and maspsx emits a BLANK LINE between them (so it
silently did nothing), and it deleted the `%hi` unconditionally, which leaves a later access
to the same global addressing a register nothing wrote -- right length, plausible, wrong.
The deletion is now gated on every use of the register before it is redefined being rewritten,
with redefinition tracked explicitly and `jalr` deliberately treated as non-defining so the
rule can only ever keep a `%hi` alive, never delete a live one.
* **`check-claims` reported a healthy CUMULATIVE file as a failure.** Worker B hit this: an
already-registered row is exactly what `apply --skip-registered` exists to skip, and a
worker's claims file is cumulative, so `result=PROBLEMS`/exit 1 was the NORMAL case for a
good file. A checker whose healthy output is a failure teaches workers to ignore its exit
code, and then it catches nothing. Already-registered is now information
(`already_registered=N`, exit 0); format errors stay exit 2, missing sources and duplicate
starts stay exit 1.
Tests: 306 -> 318, with the restriction pinned both ways (a 1-exit region is refused, a 2-exit
region is allowed), the census checked on a synthetic payload, and the gp pair rewrite's three
shapes covered. Full gate on the tracked registry stays byte-exact at 623 regions, so none of
this changes the existing corpus. `make check` exit 0.