phase12: merge 22 (665 bodies) + the pool band filter, and I had the first call backwards

MERGE 22: +2 bodies, both from worker D's un-attempted band. 0x801092C0 (52 B) and 0x80085B44 (60 B),
both re-verified by me from fresh --work dirs first. Gate: c_regions=674, differing_bytes=0, MATCH.

POOL FILTER, SECOND LEAK, MY ERROR CORRECTED. D found 0x80012D54 -- the charter-blocked 0x80012xxx
primitive-init family, with class , so the address-parsing rule I installed after the FIRST leak
(0x80012A98) had no text to match on. D read its bytes and confirmed the family.

I had explicitly DECLINED band-blocking the first time, arguing it 'would silently discard
unclassified rows on an inference the charter does not make'. That was backwards: the charter names
the family as 'the 0x80012xxx primitive-init family', i.e. BY ADDRESS BAND, and earlier phases already
acted on it -- 0x80012A10/AE0/B20/CFC, all class '-', are excluded BY NAME in the Makefile. Two rows
leaked by label phrasing and the second had no label at all. The band is the predicate. Blocked 8 -> 15,
pools 70 -> 54.

Also applying my own corrected commit idiom: this commit names the two claim sources rather than
using 'git add -A src/', which swept three of D's in-flight rows into an earlier commit.

New levers recorded: LOAD/STORE INTERLEAVING NEEDS BOTH SIDES VOLATILE (a volatile load can still
hoist above a plain store and vice versa; cc1 orders volatile only against volatile) -- and from
0x801092C0, unsigned-parameter signedness read from the instruction AFTER the test, volatile on a
table pointer for an alias reason, cookbook 19 generalising to a forward loop, and
`p += i + start; p->p0 = 0;` over the subscript form.
This commit is contained in:
Christopher Williams
2026-09-24 18:56:43 -04:00
parent 6109c3b0a9
commit bf7b6ceac2
4 changed files with 80 additions and 24 deletions
+2
View File
@@ -377,6 +377,7 @@
0x800834B8 0x80083504 src/func_800834B8.c
0x80083504 0x8008352C src/func_80083504.c
0x8008352C 0x8008355C src/func_8008352C.c
0x80085B44 0x80085B80 src/func_80085B44.c
0x80085B80 0x80085B90 src/func_80085B80.c
0x80089314 0x80089338 src/func_80089314.c
0x800893E8 0x80089434 src/func_800893E8.c
@@ -668,6 +669,7 @@
0x80108710 0x80108734 src/func_80108710.c
0x80108740 0x801087C8 src/func_80108740.c maspsx=epilogue
0x80108990 0x801089B4 src/func_80108990.c
0x801092C0 0x801092F4 src/func_801092C0.c
0x80109300 0x80109314 src/func_80109300.c
0x80109314 0x80109338 src/func_800F8F9C.c
0x80109778 0x80109790 src/func_80109778.c
1 # Code-region registry: one C region per matched function.
377 0x800834B8
378 0x80083504
379 0x8008352C
380 0x80085B44
381 0x80085B80
382 0x80089314
383 0x800893E8
669 0x80108710
670 0x80108740
671 0x80108990
672 0x801092C0
673 0x80109300
674 0x80109314
675 0x80109778
+48
View File
@@ -1049,3 +1049,51 @@ instruction count, and from the allocator class, which permutes registers — th
A spelling that moved the base's assignment after the two calls put the `la` exactly where the original
has it and changed neither the hoist nor the fourth save, which is what makes it a class rather than a
missed spelling.
### The pool filter's SECOND leak, and my first call was backwards (worker D)
Worker D found `0x80012D54` in its un-attempted band: **the `0x80012xxx` primitive-init family, which
charter section 7 blocks, and with class `-`** — so the address-parsing rule I installed after the
FIRST leak (`0x80012A98`, which at least names its siblings by address) had no text to match on. D read
the bytes and confirmed the family: `li v0,4 / sh v0,6(a0) / lui v0,0x400 / sw v0,8(a0) /
lui v0,0x5000 / sw zero,0(a0)`.
**I had explicitly declined band-blocking the first time, and the reasoning was backwards.** I argued
that blocking the whole `0x80012xxx` band "would silently discard unclassified rows on an inference the
charter does not make". But **the charter makes exactly that inference — it names the family as "the
`0x80012xxx` primitive-init family", i.e. BY ADDRESS BAND** — and earlier phases had already acted on
it, since `0x80012A10`, `0x80012AE0`, `0x80012B20` and `0x80012CFC`, all with class `-`, are excluded
**by name** in the Makefile. Two rows leaked by label phrasing, the second with no label at all, and
that is the evidence that settled it: **the band is the predicate.** Blocked rows still report their
reason. The blocked count went 8 -> 15 and the pools 70 -> **54** rows.
Recorded as a coordinator error with its correction, because the first fix looked reasonable and was
the reason the second row survived.
### Worker D's un-attempted band is producing bodies, and it was the right call to build it
D took the band I generated from its own criterion (rows with no mechanism named, never pushed to a
floor) and closed **2 of 4 rows attempted**, both at 4-6 spellings, and **both correct-LENGTH
candidates** — so the band's rows are genuinely structural rather than misidentified. D's own summary
is the one to remember: *the failures are allocator-shaped, not "wrong function"-shaped.*
**`0x80085B44` (60 B) gave the phase a sharp new lever: LOAD/STORE INTERLEAVING NEEDS BOTH SIDES
VOLATILE.** Plain C batches (`lw/lw/lw` then three stores, 25 differing bytes); `volatile int *src`
alone is still 25 bytes, **because a volatile LOAD can still hoist above a plain store**; `volatile`
globals alone is still 25 bytes, **because a volatile STORE does not stop a plain load hoisting above
it**; both together match. **cc1 orders volatile accesses only against other volatile accesses.** That
is a precise statement of a boundary that four workers have been circling all phase.
**`0x801092C0` (52 B) carried four levers, three new:**
* **UNSIGNED parameters** — `int` gives `blez`/signed `slt`, `unsigned` gives the original's `beqz`
AND `sltu`. **The entry test alone cannot tell you; the instruction AFTER it names the signedness.**
* **`volatile` on the table POINTER for an alias reason** — with a plain `Rec *` global cc1 hoists the
pointer load out of the loop, because the store's type (a pointer field of the record) is provably
not the global's own type; the original reloads every iteration. A proof by emission, not a taste.
* **Cookbook 19 generalises to a FORWARD loop** — the unused `addiu sp,sp,-8 / addiu sp,sp,8` pair
appears for `for (i=0;i<n;i++)` (64 B) and disappears with `i=0; if (n) do {...} while (++i<n);`
(52 B). Cookbook 19 recorded it for a BACKWARD loop and warned it did not generalise; this is the
second instance, so its limit tightens to "loop-shape artifact" generally.
* **`p += i + start; p->p0 = 0;` rather than `p[i + start].p0 = 0;`** — the subscript form writes the
address sum into the OFFSET's register and rotates the loop; accumulating into a pointer makes the
sum's destination the BASE register (the original's `addu v1,v1,v0`).
+22 -18
View File
@@ -151,14 +151,27 @@ BLOCKED_CLASS_SUBSTRINGS = ("trapping-arithmetic", "primitive-init")
# -- it names the blocked family **by address**, so the keyword substring test passes it straight
# through to prio 1. This is the same "half-right class string" pattern the workers kept hitting.
#
# The fix is to read the ADDRESSES out of the class text and block the row if any of them is itself
# excluded. That is deliberately preferred over blocking the whole `0x80012xxx` band, which was the
# other option D offered, **and the choice is measured**: the band holds 9 index rows and only TWO
# are the family (`0x80012A48` by keyword, `0x80012A98` by this rule). The other seven record class
# `-`, i.e. merely unclassified -- four of them are excluded by name in the Makefile anyway, and
# band-blocking would silently discard the remaining three on an inference the charter does not make.
# Rows that reference a blocked family are reported, not guessed at.
# First fix: read the ADDRESSES out of the class text and block the row if any of them is itself
# excluded. That catches `0x80012A98`, which names its family as "same family as
# 0x80012A10/0x80012AE0".
#
# **THAT WAS NOT ENOUGH, AND WORKER D FOUND THE SECOND LEAK: `0x80012D54`, whose class is `-`.**
# There is no class text to parse, so no text rule can ever catch it -- and D read its BYTES and
# confirmed it IS the family: `li v0,4 / sh v0,6(a0) / lui v0,0x400 / sw v0,8(a0) / lui v0,0x5000 /
# sw zero,0(a0)`.
#
# So the band itself is blocked, which is what the CHARTER actually says: it names the family as
# **"the `0x80012xxx` primitive-init family"**, i.e. BY ADDRESS BAND. I first declined this because
# band-blocking would discard unclassified rows "on an inference the charter does not make" -- and
# that was backwards: the charter makes exactly that inference, and it had already been acted on,
# since `0x80012A10`, `0x80012AE0`, `0x80012B20` and `0x80012CFC` (all class `-`) are excluded BY NAME
# in the Makefile. **Two workers found the leak twice and the second instance had no text to match on,
# which is the evidence that settled it.** Blocked rows are still REPORTED with their reason.
FAMILY_ADDRESS_RE = re.compile(r"0[xX][0-9A-Fa-f]{6,8}")
BLOCKED_ADDRESS_BANDS = (
# The charter's own wording. See the comment above for why the band, not a string.
(0x80012000, 0x80013000, "charter s7: the `0x80012xxx` primitive-init family"),
)
# *** THE TRIAGE KEY WAS IMPLEMENTED, TESTED AGAINST THE PHASE'S OWN RECORD, AND IT FAILED ***
#
@@ -427,9 +440,6 @@ def main():
dropped_done = []
dropped_blocked = []
dropped_own = []
# Rows in a charter-named FAMILY band that the index never classified. Not blocked on an
# inference, but reported, so a human can decide rather than having it decided silently.
unclassified_family_band = []
for addr, size, status, klass in unregistered:
bucket = names[zlib.crc32(f"{addr:#010x}".encode()) % args.workers]
# CHARTER SECTION 7. A blocked class must not be attempted at all, so it must not be
@@ -438,7 +448,9 @@ def main():
blob = f"{status} {klass}".lower()
# A family reference BY ADDRESS counts exactly like a keyword. D's `0x80012A98` case.
family_refs = {int(x, 16) for x in FAMILY_ADDRESS_RE.findall(klass or "")}
band = next((reason for lo, hi, reason in BLOCKED_ADDRESS_BANDS if lo <= addr < hi), None)
if ("blocked" in status
or band is not None
or any(s in blob for s in BLOCKED_CLASS_SUBSTRINGS)
or (family_refs & (excluded | blocked_addrs))):
dropped_blocked.append((addr, bucket, status, klass))
@@ -469,8 +481,6 @@ def main():
prio = min(prio, 2)
if "deferred" in status:
prio = 4
if 0x80012000 <= addr < 0x80013000 and not (klass or "").strip().strip("-"):
unclassified_family_band.append((addr, bucket))
# A NOTE column, because free-text staging cannot be parsed reliably enough to decide
# "done" vs "cheap retry" in every case. Where the tool CAN decide it drops the row (the
# absence-token case, above); where it cannot, it says who classified it and lets the worker
@@ -533,12 +543,6 @@ def main():
if len(dropped_done) > 5:
print(f" ... and {len(dropped_done) - 5} more")
print(f" dropped, this bucket's OWN prior classification {len(dropped_own)}")
if unclassified_family_band:
print(f" NOT blocked but FLAGGED: {len(unclassified_family_band)} row(s) inside a"
f" charter-named family band that the index never classified:")
for addr, bucket in sorted(unclassified_family_band):
print(f" {addr:#010x} (pool {bucket}) -- class '-', so the charter's family"
f" membership is an INFERENCE, not a record. Decide deliberately.")
print(f"pool rows written {sum(written.values())}"
f" (check: {len(unregistered) - len(leaked) - len(dropped_done) - len(dropped_blocked) - len(dropped_own)})")
for n in names:
+8 -6
View File
@@ -278,15 +278,17 @@ class TestSyntheticPools(unittest.TestCase):
self.assertEqual(self.pool_rows(), [],
"a class naming an EXCLUDED address is a family reference, not a pass")
def test_a_family_band_row_with_no_class_is_flagged_not_blocked(self):
"""The other option D offered was to block the whole `0x80012xxx` band. Measured: the band
holds 9 index rows and only TWO are the family. Blocking by prefix would silently discard
unclassified rows on an inference the charter does not make, so they are KEPT and reported."""
def test_a_family_band_row_with_NO_CLASS_is_blocked(self):
"""I first kept these rows, arguing that blocking by band discards unclassified rows on an
inference the charter does not make. Worker D then produced `0x80012D54`: class `-`, no text
to match on, and its BYTES confirm it IS the family. The charter names the family BY BAND
("the `0x80012xxx` primitive-init family"), and earlier phases already excluded four class-`-`
band rows by name -- so the band is the right predicate and my first call was backwards."""
self.write_negatives([("0x8001278C", "-", "near-match")])
r = self.run_tool()
self.assertEqual(r.returncode, 0, r.stderr)
self.assertEqual(len(self.pool_rows()), 1,
"an unclassified band row is not blocked, only flagged")
self.assertEqual(self.pool_rows(), [],
"the charter names the family by BAND, and class `-` cannot be matched on")
def test_rare_epilogue_order_is_NOT_blocked(self):
"""Worker A's distinction: the epilogue ORDER is work (cookbook 140/147/165 shipped