phase11: ledger + CURRENT_PHASE at the compaction point — 501 bodies / 510 regions
Records worker B's oracle result overturning the post-pass framing (ASPSX does not fill delay slots; maspsx is faithful to it; the fills come from GNU as reorder mode and the only gap is one mnemonic), the new `maspsx=moves` mode, worker C's correction of a too-broad Phase 10 coordinator fix (now opt-in `maspsx=nopmarker`), the per-worker cost tables that show SHAPE not band is the variable, and the new findings 63-66 plus the named-locals family's fourth mechanism and the char[4] block-move recipe. Committed at the orchestrator's 70% context cap; compaction follows, safe because the ledger and CURRENT_PHASE are current.
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
# CURRENT_PHASE — Phase 11: Breaking the 244-Byte Ceiling
|
||||
|
||||
**Status:** ACTIVE (P11-T1 in progress)
|
||||
**Status:** ACTIVE (cycle 1). **501 distinct bodies / 510 regions** from the 484 / 493 baseline.
|
||||
Corpus maximum **700 B** (worker D's `0x8006BC74`). Two harness modes added this phase:
|
||||
`maspsx=moves` (the `move`->`addu` rewrite with maspsx off, from worker B's ASPSX oracle result)
|
||||
and `maspsx=nopmarker` (opt-in correction of a too-broad Phase 10 fix). See
|
||||
`phase-ends/logs/Phase11.md` for the running ledger — it is the durable record.
|
||||
**Created:** 2026-09-24, after Phase 10 closure and developer approval of `phase-ends/Phase11_PLAN.md`.
|
||||
**Milestone:** **600 distinct matched bodies** from the Phase 10 close of 484 (**+116**), with **700 as a
|
||||
stretch**, measured on the orchestrator's clean whole-binary gate.
|
||||
|
||||
@@ -225,3 +225,81 @@ Suite 237 → 246 tests. The candidate gate caught the bad row; the tracked regi
|
||||
**Ranks are not stable — key dispatch by address.** Worker D's row moved from rank 592 to 578 mid-session
|
||||
because the worklist regenerates and the partitions refilter after every merge. **Addresses are stable;
|
||||
ranks are not**, and rank-keyed scratch tooling drifts silently onto a different row.
|
||||
|
||||
## Cycle 1 continued — the 700 B match, the `moves` mode, and a coordinator-fix correction
|
||||
|
||||
**501 distinct bodies / 510 regions** (from 484 / 493). Corpus maximum **700 B** (worker D's
|
||||
`0x8006BC74`), 2.9x the old 244 B ceiling and the first match in the 401–800 B band.
|
||||
|
||||
### Worker B's oracle result OVERTURNED the post-pass framing
|
||||
|
||||
Worker B ran all five SDK assemblers (ASPSX 2.56/2.67/2.79/2.81/2.86) and every supported option as a
|
||||
read-only oracle and found that **ASPSX does NOT fill delay slots at all** — it produces maspsx's exact
|
||||
shape. So **maspsx is faithful to ASPSX**, and the fills in the original did not come from ASPSX. That
|
||||
kills the "model ASPSX's fill" framing the developer had authorized a post-pass for.
|
||||
|
||||
**What actually fills the slots is GNU `as` in reorder mode — i.e. maspsx OFF** — and the only real gap is
|
||||
**one mnemonic**: `as` expands cc1's `move` to `or` where ASPSX emits `addu`.
|
||||
|
||||
**New harness mode `maspsx=moves`** = `maspsx=off` plus a single `move`→`addu` rewrite, letting `as` fill
|
||||
exactly the slots cc1 left empty while cc1's own `.set noreorder` windows are preserved. Demonstrated:
|
||||
`0x800FA5D8` gives **132 B / 0 differing MATCH** where default maspsx gives 148 LENGTH-MISMATCH.
|
||||
Regression-verified at 510 regions with the mode off. Opt-in per region, because worker B measured the
|
||||
counterexample `0x8002D2BC` — the *same* cc1 shape, but its original keeps the store before the `jr` with
|
||||
a nop, so the original's assembler behaves differently in different files.
|
||||
|
||||
### A coordinator fix from Phase 10 was TOO BROAD — corrected by a worker
|
||||
|
||||
Worker C found, while characterising an above-ceiling row, that Phase 10's unconditional
|
||||
"honour cc1's explicit `#nop` marker" is wrong for a **bare-symbol store consumer**: the store's own
|
||||
`lui $at` expansion **fills the delay slot**, so the marker is **spurious**, and honouring it costs an
|
||||
instruction (`0x800AFDBC`: the original is `lhu` / `lui at` / `sh` with no nop). But `0x80107C5C`
|
||||
genuinely wants the nop (112 vs 108).
|
||||
|
||||
Two rows wanting opposite behaviour from the same shape ⇒ **make it a per-region mode**:
|
||||
`maspsx=nopmarker`, **default OFF**. Verified: `make check` green at 510 regions / 253 tests with it off;
|
||||
`0x80107C5C` matches 112 B with the token and is 108 B LENGTH-MISMATCH without it. Patch regenerated and
|
||||
verified; `SETUP.md` records the correction.
|
||||
|
||||
**The pattern is worth naming:** a fix proven regression-free against the **corpus** can still be wrong
|
||||
for an **unmatched** row, because the corpus only exercises the paths that already work.
|
||||
|
||||
### Cost and shape — two workers, converging
|
||||
|
||||
| source | band | rows | matched | cost |
|
||||
|---|---|---|---|---|
|
||||
| worker D | >244 B | 5 | **4 (80%)** | 2–7 spellings, including 700 B in 3 |
|
||||
| worker D | ≤244 B (paired control) | 1 | 1 | first spelling |
|
||||
| worker C | >244 B | 4 | 1 (25%) | median **11.5 attempts**, every failure ≤8 bytes |
|
||||
|
||||
**The band is not the variable — the shape is.** D's rows have **repetitive bodies** (reset/init/copy),
|
||||
where redundancy makes a large body cheap. C's three near-misses are **tie-break-dense** bodies where the
|
||||
size is incidental. So: **repetitive bodies are cheap at any size; tie-break-dense bodies are expensive at
|
||||
any size.** That is the refinement of finding 58, and it points at redundancy rather than size as the
|
||||
ranking signal.
|
||||
|
||||
### New findings
|
||||
|
||||
- **Cookbook 63** — the **combiner constant-fold class**: a residual of exactly one `addiu` plus a
|
||||
matching shift in *every* displacement of one base register means cc1 folded a constant offset the
|
||||
original kept in a register; materialise the offset as a named local. Invisible to a mnemonic diff.
|
||||
- **Cookbook 64** — finding 59's family has three load-bearing properties, one per instance: row stride,
|
||||
total size, **memory residence**.
|
||||
- **Cookbook 65** — the amendment to finding 41 is **measured**: the paired control matched first try, so
|
||||
the lever set was the variable, not the band. And the two **largest** bodies were the **easiest**.
|
||||
- **Cookbook 66** — a bounded negative with a **named direction** beats a blocked class.
|
||||
- **Named-locals family, FOURTH mechanism, opposite polarity** (worker D, `0x800FF5A8`): name **two**
|
||||
pointer locals both holding `a0` and both live across the call — the allocator cannot coalesce
|
||||
overlapping live ranges, so a second callee-saved register appears. The recorded cases are "name a
|
||||
local so cc1 does NOT reload"; this is "name a local so cc1 MUST keep a second copy".
|
||||
- **The `char[4]` struct-copy loop is the block-move idiom** (worker C): an explicit
|
||||
`for (i=0;i<40;i++) dst[i] = src[i];` over a 4-byte `char[4]` struct yields `lwl`/`lwr` + `swl`/`swr`
|
||||
with **no runtime check**, while a 160-byte struct assignment makes cc1 emit a runtime alignment test
|
||||
plus two loops (344 B, +96).
|
||||
- **A local holding a constant is not free** (worker C): naming `127` forced an `s1` save and grew the
|
||||
frame 48 → 56.
|
||||
|
||||
### Orchestrator note
|
||||
|
||||
Context reached the 70% cap and was **compacted** rather than stopped, per the phase policy — safe because
|
||||
the ledger, `CURRENT_PHASE.md`, the tracked registries and the negatives index are all current.
|
||||
|
||||
Reference in New Issue
Block a user