phase12: fragment predicate, D's twin correction (coordinator error), and the redundant-flag lesson

This commit is contained in:
Christopher Williams
2026-09-24 18:18:49 -04:00
parent 228ad953e4
commit ab5b2d3857
+87
View File
@@ -624,3 +624,90 @@ New pools, split by `crc32(address) % 4` so membership cannot move:
**176 unregistered negatives rows; 92 carry a named mechanism; 8 are in the multi-exit `cc1bin`
class.** D was told to take its **three in-flight `wip` twins first** (`0x800161E0`, `0x80016224`,
`0x8008F478`) before the pool, because twins have closed at one spelling all phase.
### The FRAGMENT class gets a predicate (worker D + coordinator, independent agreement)
Worker D, sweeping the GTE batch, hit `0x8001DC20` (72 B) and **refused to spend GTE spellings on
it**, reporting it as a fragment: its first instruction is `lw t0,0(t5)` and `t5` is never
established in the extent. That is cookbook 114/141's signature, and D's read was that it is **not**
a GTE-lever problem.
I re-derived the conclusion from the bytes before acting on it (a worklist/registry change is a state
change, so the evidence rule applies):
| row | first insn | instructions WRITING `$13` in the extent |
|---|---|---|
| `0x8001DC20` (72 B) | `0x8DA80000` = `lw t0,0(t5)` | **0** |
| `0x800C3490` (132 B) — already excluded | `0xAFA20020` | **0** |
**The class now has a checkable predicate instead of a vibe:**
> A caller-saved temporary (`$8`-`$15`, `t0`-`t7`) is READ before any instruction in the extent
> WRITES it ⇒ the extent is the tail of a larger function, not a function.
This is **sound**: `$8`-`$15` are never incoming o32 arguments (those are `$4`-`$7`), and no compiler
emits a read of an uninitialised temporary. It is **not yet an automatic triage rule** — that needs a
fail-first test, so it is recorded as an open item rather than half-implemented at the context cap.
Until it is implemented, fragments are caught by a worker reading the row, which has now cost **two
workers a reading budget each** (`0x800C3490` twice, `0x8001DC20` once).
### The counter caught the coordinator's own redundant flag
I added `--exclude 0x8001DC20` to the worklist target and **the counter did not move**:
`excluded_named_exclusion` stayed **9**. That is the tool telling me the row was *already* excluded
from the worklist (`excluded_recorded_negative` = 154 covers it), so the flag was **redundant**. D's
row reached D through the **negatives pool**, which is generated separately from the worklist and
from a different file — **that** is where the gap is, not the worklist.
The `--exclude` line and its comment are retained, because the predicate and the two worked instances
are the durable part, but the exclusion itself was already in effect and **the commit does not claim
otherwise**. Recording this because the counter catching a redundant action is the same mechanism
that has caught several real defects this phase, and it should be read as a signal rather than noise.
### Worker D corrects the coordinator's twin expectation
I told D its three in-flight twins were "the best-value rows available anywhere" because twins have
closed at one spelling all phase. **That was wrong for one of the three, and it cost D 11
spellings.** D reported the correction:
> "Twins close at one spelling" holds when the partner is **REGISTERED** (there is a body to copy).
> It **cannot** hold when both members are pool rows — there is nothing to copy and the pair needs a
> full derivation.
`0x800161E0`/`0x80016224` (68 B each) are twins of **each other** with **no registered parent**;
`0x8008F478` (40 B) is the alignment-tolerant twin of the registered `0x80024C14`. So the instrument
must label each pair **registered-parent** vs **both-pool** — one is a one-attempt row, the other a
full derivation, and the map could not tell them apart. Worker C has been asked to add the label and
to order `twin-map.md` registered-parent-first.
**Coordinator error, recorded as such.** The dispatch decision was made from a good measurement
("twins close at one spelling") applied without checking which side of that line each row was on.
### Worker D's three twin outcomes (all three are negatives, each with a named mechanism)
* `0x800161E0`/`0x80016224` — correct structure and length, **4 differing bytes / 3 missing
`move v0,...`**. cc1 ties the walk pointer (the returned value) to `v0`, so the return copies
coalesce away and the LOADED FIELD takes `a0`; the original keeps the pointer in `a0` (the
parameter's own home) and copies `a0`→`v0` into each branch delay slot. **11 spellings.**
No source-shape lever left — allocator class.
* `0x8008F478` — **exactly 2 words differ and BOTH ARE THE PROLOGUE**: original
`sltiu a0,a0,1 / sb a0,3364(gp) / sw ra,16(sp)` vs cc1 `sltiu / sw ra / sb`. Same multiset, same
length, 8 bytes, **robust across 5 spellings**. Scheduler class. `-fno-schedule-insns2` is
**unusable** here (it takes the row to 72 B). Also: **`D_8012265C` = `gp+0xd24` already HAS a gp
row (cookbook 14)** — D corrected a coordinator note that said this row needed a new one; it does
not.
* `0x8001DC20` — fragment, above.
### `0x801097A0` (128 B) — the phase's first genuine inline-asm row, authorised
A GTE/COP0 setup row: save `ra` to a global at `0x80120FF8`, call `func_8010B420`, restore `ra`, then
`mfc0/or/mtc0 $12`, then `ctc2` into `$29` (341), `$30` (256), `$26` (1000 = H), `$27` (-4194 = DQA),
`$28` (`0x1400000` = DQB), `$24`/`$25` = 0, each with an explicit latency `nop`. Needs
(a) `register int ra __asm__("$31")` for the save/restore — **documented GNU C, no exemption
required** — and (b) raw `ctc2` for `$29`/`$30` because `include/gtemac.h` **stops at `$28`**.
Authorised, and the macros go into `gtemac.h` the way the existing ones were added from
`0x800F3BB4`'s row. Assigned to D.
**Worth naming:** the GTE inline-asm hatch authorised earlier for `0x80010810`/`0x8009C69C` **was
never used** — worker C matched both in plain C. So this would be the phase's first real asm row,
which is a milestone and not a shortcut.