docs(cookbook): §424 - equal-priority stores emit REVERSED (sched1 LUID tie picks the last statement)

Byte-proven on ov_SC07_006/func_801890FC (387 ins). For two stores at equal priority,
sched1's LUID tie picks the LAST statement's store first; regalloc then gives the other
load $v0, where it sits behind its own $v0 predecessors, and sched2 pins that chain last.
Each equal-priority pair therefore appears reversed: source FE;E-=0x40;A-=0xEE;88;8A;8C
emits as E,88,A,8C,8A.

This is why "statement order is inert" is such a common wrong conclusion here - the
mapping is not identity, so trying orders at random explores the wrong space. Compute the
intended emission order, then invert each equal-priority pair.

Companion (§193-E): the prior draft left no different-address store between `sh 0xA` and
its re-read, so cse forwarded it as `andi 0xffff`. A store to a different address between
the two re-seeds cse - §416's "re-read the store" seen from the failure side.
This commit is contained in:
Drew T
2026-09-02 10:22:16 -06:00
parent 9a94d0593d
commit 1e314e7208
2 changed files with 27 additions and 2 deletions
+5 -2
View File
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
> `docs/matching-cookbook.md` is ~716 KB / 1091 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
> `docs/matching-cookbook.md` is ~716 KB / 1092 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -102,7 +102,7 @@
- **§370** — ★★ — A **HARD BOUND** FROM sched.c, AND THE reorg SLOT-STEAL DIAGNOSTIC (P31 S68; main/func_8001BC6C, 69 ins, NOT closed — 33 → 28 over ~45 measured compiles) <sub>L31838</sub>
- **§396g** — ★★ — A GUARD LADDER'S RUNGS MUST STAY SYMMETRIC OR `reorg.c` LOSES ITS BRANCH REDIRECT (P31 S69; byte-proven ov_SC03_028/func_80184C90, 92 ins) <sub>L32818</sub>
### instruction scheduling (86)
### instruction scheduling (87)
- **§3-T2** — Source statement order drives instruction scheduling <sub>L78</sub>
- **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) <sub>L107</sub>
@@ -190,6 +190,7 @@
- **§385** — ★★★ — THE **SCHED2 PRIORITY-DONOR ASM**: closing the "hoisted-invariant vs IV-init preheader swap" class (P31 S69; byte-proven main/func_80038A58, 347 ins, fable escalation 2 → 0) <sub>L32309</sub>
- **§393** — ★★ — THE **BIRTHING BOOST**: A SINGLE-SET LOCAL IS SCHEDULED LAST; GIVE IT A SECOND SET (P31 S69; byte-proven ov_SC02_017/func_8017FCFC) <sub>L32543</sub>
- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) <sub>L33108</sub>
- **§424** — ★★★ — EQUAL-PRIORITY STORES COME OUT **REVERSED**: sched1's LUID tie picks the LAST statement first (P31 S71; byte-proven `ov_SC07_006/func_801890FC`, 387 ins) <sub>L33807</sub>
### register allocation & pins (131)
@@ -2772,6 +2773,7 @@
- **§421** — ★★★ — A `la $tN` + `addiu` PAIR CAN BE A **RELOAD** ARTIFACT THAT NO C SPELLING REACHES (P31 S71; byte-proven `md_SC07_003/func_801A293C`, 313 ins, 6 → 0) <sub>L33729</sub>
- **§422** — ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte-proven `resident/func_800D06E8`, 344 ins) <sub>L33760</sub>
- **§423** — ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE-SCOPE TYPEDEF THE DRAFT ALSO CARRIES (P31 S71; byte-proven `ov_SC03_092/func_8017FA74`) <sub>L33780</sub>
- **§424** — ★★★ — EQUAL-PRIORITY STORES COME OUT **REVERSED**: sched1's LUID tie picks the LAST statement first (P31 S71; byte-proven `ov_SC07_006/func_801890FC`, 387 ins) <sub>L33807</sub>
---
@@ -3875,3 +3877,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
| L33729 | §421 | ★★★ — A `la $tN` + `addiu` PAIR CAN BE A **RELOAD** ARTIFACT THAT NO C SPELLING REACHES (P |
| L33760 | §422 | ★★ — QImode ARITHMETIC VIA `(u8)(x - K)`, AND `flag ^ 1` NEEDS ITS OWN TEMP (P31 S71; byte |
| L33780 | §423 | ★★★ — "MATCH IN ISOLATION + GATE REJECTS + CAUSE NOT DETERMINED" ⇒ GREP THE TU FOR A FILE- |
| L33807 | §424 | ★★★ — EQUAL-PRIORITY STORES COME OUT **REVERSED**: sched1's LUID tie picks the LAST statem |
+22
View File
@@ -33803,3 +33803,25 @@ the TU defines that name.**
exits 1 on its relative `"../shared/engine_core.h"` — and then **every variant "passes" identically**,
which is a silent all-green instrument. Negative-control any TU-splice harness against an unmodified
copy before believing a single verdict from it.
## §424 ★★★ — EQUAL-PRIORITY STORES COME OUT **REVERSED**: sched1's LUID tie picks the LAST statement first (P31 S71; byte-proven `ov_SC07_006/func_801890FC`, 387 ins)
**The symptom.** A run of same-shape halfword stores appears in the asm in an order that looks
scrambled relative to any source order you try — and statement reordering seems to do nothing useful,
because every order you try is wrong in the same way.
**The mechanism, read off `-dS`/`-dR` against `docs/gcc-2.7.2-map/sched.md`.** For a pair of stores at
EQUAL priority, sched1's LUID tie picks the **last statement's** store first. Regalloc then hands the
OTHER load `$v0` — where it is stuck behind its own `$v0` predecessors — and sched2 pins that chain
last. Net effect: **each equal-priority pair appears reversed in the output.** Measured here, source
order `FE ; E-=0x40 ; A-=0xEE ; 0x88= ; 0x8A= ; 0x8C=` emits as `E, 88, A, 8C, 8A`.
**So write the source in the order that INVERTS pairwise**, rather than the order you want to read in
the asm. This is why "statement order is inert" is such a common (and wrong) conclusion on these
functions: the mapping is not identity, so trying orders at random explores the wrong space. Compute
the intended emission order, then invert each equal-priority pair.
**The companion defect on the same function (§193-E).** The prior draft's temps left **no
different-address store between `sh 0xA` and its re-read**, so cse forwarded the value and emitted
`andi 0xffff` instead of the reload. A store to a different address between the two is what re-seeds
cse — the same lever as §416's "re-read the store", seen from the failure side.