diff --git a/docs/SETUP.md b/docs/SETUP.md index f28f58e..bf16bf2 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -88,6 +88,14 @@ 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 + 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 + (`0x80107C5C`, `0x8003A9C8`). The fix honours the marker instead of overruling it. **Verified + regression-free: `make check` green at 489 regions / 237 tests with all 489 regions byte-identical.** + Worker B2 found the gap; the coordinator traced the mechanism after B2's first diagnosis (extend the + predicate) proved to be a no-op — the predicate already returned True. Both default **off**, and `make check` is green at 439 regions with them off, so the matched corpus is byte-identical. **Status: implemented, but neither mode has been shown to close a region.** See diff --git a/tools/patches/maspsx-phase10-r1r2.patch b/tools/patches/maspsx-phase10-r1r2.patch index 5301b56..4204a89 100644 --- a/tools/patches/maspsx-phase10-r1r2.patch +++ b/tools/patches/maspsx-phase10-r1r2.patch @@ -64,7 +64,7 @@ self.sltu_at = sltu_at self.addiu_at = addiu_at self.div_uses_tge = div_uses_tge -@@ -696,7 +739,14 @@ +@@ -696,9 +739,30 @@ ) -> List[str]: res: List[str] = [] @@ -79,8 +79,24 @@ + if reuse: nop_required = False ++ # Phase 10 (developer-authorised): cc1 emits an explicit `#nop` 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`) ++ # `uses_at` is True (the store expands via $at) while `nop_at_expansion` ++ # is False for ASPSX >= 2.30, so neither test below fired and the nop was ++ # dropped -- losing an instruction cc1 had asked for (0x80107C5C, ++ # 0x8003A9C8). Honour the explicit marker instead of overruling it. ++ # Only the marker changes behaviour; every other path is untouched. ++ if self.get_next_instruction( ++ skip=0, ignore_nop=False, ignore_set=True, ignore_label=True ++ ) == "#nop": ++ reason = "cc1 emitted an explicit '#nop' marker" ++ nop_required = True ++ if not uses_at(next_instruction): -@@ -1102,7 +1152,7 @@ + reason = f"'{next_instruction}' does not use $at" + nop_required = True +@@ -1102,7 +1166,7 @@ elif op in branch_mnemonics or op in jump_mnemonics: res.append(line)