phase11: CORRECTION — the Phase 10 #nop-honouring fix was TOO BROAD; now opt-in (maspsx=nopmarker)

Worker C found the defect while characterising an above-ceiling row: the Phase 10 fix
that made maspsx honour cc1's explicit `#nop` marker unconditionally is wrong for a
bare-symbol store consumer, because the store's own `lui $at` expansion fills the
delay slot and the marker is SPURIOUS. On 0x800AFDBC the original is
`lhu` / `lui at` / `sh` with NO nop, and honouring the marker costs 2 instructions --
turning a row that was otherwise byte-identical into a LENGTH-MISMATCH.

But the fix is genuinely needed for 0x80107C5C (112 vs 108). So the two rows want
opposite behaviour from the same instruction shape, and the honest resolution is to
make it a per-region mode rather than a global default.

  `maspsx=nopmarker`  ->  --honour-nop-marker   (default OFF)

VERIFIED BOTH WAYS:
  make check with the mode OFF   -> regions=510 AGREE, differing_bytes=0 MATCH, 253 tests OK
  0x80107C5C WITH the mode       -> 112 B, differing_bytes=0 MATCH
  0x80107C5C WITHOUT it          -> 108 B LENGTH-MISMATCH
So the default is the long-standing behaviour, and rows that need the marker opt in.

The tracked patch is regenerated and verified to reproduce both modified files exactly
from the pristine pinned checkout (tools/maspsx is git-ignored, so the patch is the only
reproducible carrier). docs/SETUP.md records the correction.

This is the third time this phase a worker found a defect in work the coordinator had
already shipped as verified -- the pattern is worth noting: 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.
This commit is contained in:
Christopher Williams
2026-09-24 09:15:47 -04:00
parent 55e59b3a4a
commit c4f4bc0cfa
3 changed files with 48 additions and 26 deletions
+9 -1
View File
@@ -88,7 +88,15 @@ patch, and diffing the result against the working tree (byte-identical). It adds
after a branch/jump so GNU `as` can fill the slot.
- `--nop-on-reg-read` (region token `maspsx=regread`) — extend the load-delay predicate (cookbook
finding 27) so a following `jr`/`jalr` that *uses* the loaded register also gets the delay `nop`.
- **A default-on fix (no region token): maspsx now honours cc1's explicit `#nop` marker.** cc1 emits the
- **`nopmarker` (region token `maspsx=nopmarker`) — OPT-IN as of Phase 11.** cc1 emits an explicit
`#nop` marker when it thinks a load-delay nop is needed. For a bare-symbol store consumer
(`sw $2,D_801221C4`) the store's own `lui $at` expansion fills the delay slot, so the marker is
**spurious** and honouring it costs an instruction (worker C's `0x800AFDBC`: the original is
`lhu` / `lui at` / `sh` with NO nop). But `0x80107C5C` genuinely wants the nop (112 vs 108).
Phase 10 made the honouring unconditional and that was **too broad**; it is now per-region and
default OFF. Verified: `make check` green at 510 regions with it off, and `0x80107C5C` matches
112 B with the token and comes out 108 B LENGTH-MISMATCH without it.
- **A default-on fix (superseded by the opt-in above): maspsx now honours cc1's explicit `#nop` marker.** cc1 emits the
marker when it wants a load-delay nop; maspsx used to re-derive the need and could overrule cc1 for a
**bare-symbol store** consumer (`sw $2,D_801221C4`), because `uses_at` is True for a macro store while
`nop_at_expansion` is False for ASPSX >= 2.30, so neither test fired and the nop was dropped