mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-05 08:57:59 -04:00
docs(phase-31): cookbook §179 — eight idioms mined from the wave P/Q journals (S52 harvest)
12 reader agents over 172 substantial agent findings from waves P and Q; 16 survived their novelty
filter; merging duplicates and dropping what §174-§178 already own left EIGHT levers. The
synthesizer re-read every gcc/maspsx/masked_diff citation and corrected three wrong line numbers
inline; I independently re-verified two of them (loop.c:3500 `src = SET_SRC (bl->init_set)`,
valid_initial_value_p at :3509, bl->initial_value at :3511; and maspsx's tab-literal `.set\t` test
at __init__.py:844-848) -- both exact.
A. A loop-walked pointer PARAMETER hands its argument register to the giv (9 byte-proofs).
record_initial records assign_parms' own incoming-argument copy as the biv's init_set, so
emit_iv_add_mult re-references the HARD register in the preheader, extending $aN's live range
and costing the parameter its hard-reg tie. Fix: body-local copy, or an identity re-tie whose
ASM_OPERANDS SET_SRC makes valid_initial_value_p refuse. Explicitly paired with §70, which
documents the SAME chain used in the opposite direction.
B. The hand-written-asm transcription checklist (10 byte-proofs): `.set` needs a literal TAB or
maspsx never updates is_reorder and re-nops every branch; `.ent` does not update it either;
displacements must be DECIMAL (bare int() before the range check); maspsx's LOAD-delay nop is
UNCONDITIONAL, so you manage branch-delay nops and must NOT manage load-delay ones; internal
labels need a `.L` prefix or masked_diff truncates the function at the stray symtab entry.
Also flags a real CONFLICT with the banked trampoline rules and gives the A/B to resolve it.
C-H. No-epilogue functions must be file-scope __asm__; gte_stflg must clobber $12; a
>2*MAX_MOVE_BYTES copy is a struct assignment; pinning a walked pointer disables strength
reduction entirely; a pin can CREATE a combine LOG_LINK (n=1, marked as such); a mid-body
.global pair slices a byte-comparable fragment.
Ends with a "considered and NOT banked" list -- including a softened claim where the reader's
derivation was not traced line-by-line, and a corrected symbol typo. Nothing silently dropped.
Cookbook 554 -> 564 sections.
This commit is contained in:
+54
-29
@@ -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 / 554 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 / 564 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.
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
- **§162** — CROSS-JUMP DIRECTION: the surviving copy is always the LATER one, so a BACKWARD `j` into a sibling arm is a source `goto` (P30 S48) <sub>L11263</sub>
|
||||
- **§162** — The cross-jump "CALL veto" is a COUNT law, not a CALL law (BOUNDS §88a; P30 S48, `func_80189540`) <sub>L11299</sub>
|
||||
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17306</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
|
||||
|
||||
### instruction scheduling (24)
|
||||
|
||||
@@ -69,10 +69,10 @@
|
||||
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
|
||||
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
|
||||
- **§3-B.** — A `return <const>` IS A PRIORITY-1 HARD-REG SET THE SCHEDULER PLACES FIRST (func_8001BE30, 92 ins) <sub>L17230</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17306</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17370</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
|
||||
|
||||
### register allocation & pins (48)
|
||||
### register allocation & pins (51)
|
||||
|
||||
- **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) <sub>L835</sub>
|
||||
- **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register <sub>L856</sub>
|
||||
@@ -119,18 +119,21 @@
|
||||
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
|
||||
- **§176j** — STOPPING A WAVE MID-FLIGHT COSTS THE IN-FLIGHT TAIL (and how much is recoverable) <sub>L17093</sub>
|
||||
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17300</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17330</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17370</sub>
|
||||
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
|
||||
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
|
||||
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17596</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
|
||||
|
||||
### CSE / redundancy / rematerialization (4)
|
||||
|
||||
- **§46** — The `func_80178D40` crack (890 ins ×134, the heaviest core in the game): four LOOP-STRUCTURE levers cheap-Opus found by reading loop.c/jump.c/cse.c (Phase 26 session 8, 2026-07-13) <sub>L3313</sub>
|
||||
- **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom <sub>L6452</sub>
|
||||
- **§153** — THE ADDRESS-REMATERIALISATION LAUNDER: a third zero-emission asm lever (P30 S43, `func_8018D98C`, 710 ins) <sub>L10463</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17396</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17692</sub>
|
||||
|
||||
### loops & induction variables (10)
|
||||
### loops & induction variables (13)
|
||||
|
||||
- **§3-T1** — Loop pointer: top-of-body for `addu` induction, not constant-folded `addiu` <sub>L71</sub>
|
||||
- **§34** — The `func_80138ED0` giant crack: gcc-2.7.2's **3-qty sort bug** + the **zero-byte asm allocation toolkit** + the **giv-init fence** (Phase 24 T5; Opus→close=21, Fable5→MATCH ×134) <sub>L2454</sub>
|
||||
@@ -142,8 +145,11 @@
|
||||
- **§145** — Three loop/combine levers from the S40 wave-2 drafters (16/16 match_one) <sub>L9924</sub>
|
||||
- **§148** — The loop.c hoisting THRESHOLD is arithmetic you can compute, and the `?:` clamp that folds to MIN_EXPR (P30 S42, `func_8017C6F4`, 947 ins) <sub>L10142</sub>
|
||||
- **§171a** — THE MECHANICAL A-PROP DRAFT (P30 S50): 256 members banked with no agent in the loop <sub>L16417</sub>
|
||||
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
|
||||
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
|
||||
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
|
||||
|
||||
### structs, block moves & memcpy (38)
|
||||
### structs, block moves & memcpy (39)
|
||||
|
||||
- **§3-T2** — Source statement order drives instruction scheduling <sub>L78</sub>
|
||||
- **§5** — Known hard-residual classes (instruction-identical, one byte-exact blocker) <sub>L199</sub>
|
||||
@@ -182,7 +188,8 @@
|
||||
- **§3-The** — ADDRESS-CLASS TABLE: which load/store pairs even REACH the `/s` clause (P30 S48 wave 4, `func_80185B44`, ov_SC03_014) <sub>L14339</sub>
|
||||
- **§176g** — SIZE A WAVE BY INSTRUCTIONS, NOT BY CARDS (P31 S52 — the adopted doctrine) <sub>L16927</sub>
|
||||
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17267</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17330</sub>
|
||||
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
|
||||
|
||||
### types, signedness & load/store width (36)
|
||||
|
||||
@@ -284,7 +291,7 @@
|
||||
- **§168** — THE COUSIN TIER (P30 S49, 2026-08-12): h_seq's exact-hash brittleness, measured — and the similarity map above it <sub>L16208</sub>
|
||||
- **§176f** — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52) <sub>L16896</sub>
|
||||
|
||||
### jump tables & switches (27)
|
||||
### jump tables & switches (28)
|
||||
|
||||
- **§8** — rodata island (compiler jump tables) — the `.data→.rodata→.data` sandwich (Phase 7) <sub>L320</sub>
|
||||
- **§8a** — rodata island in a flat OVERLAY — the tail sandwich, per matched jr-function (Phase 26 — PoC PROVEN) <sub>L342</sub>
|
||||
@@ -313,6 +320,7 @@
|
||||
- **§132b** — When the span's already-matched owner is ITSELF multi-switch: `--span-rel` (P30 S1, `func_8014032C`) <sub>L8660</sub>
|
||||
- **§139** — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished) <sub>L9591</sub>
|
||||
- **§161** — THE RETRY-WAVE HARVEST: a jump table indexed from zero, and two allocator traps (P30 S47) <sub>L10966</sub>
|
||||
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
|
||||
|
||||
### optimisation level (-O0/-O2) (12)
|
||||
|
||||
@@ -463,7 +471,7 @@
|
||||
- **§173** — THE STORED-PLUMBING RECOVERY RECIPE (P31 T6): symfix-first, per-group isolation, and where the verdicts have no drafts <sub>L16603</sub>
|
||||
- **§176d** — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15) <sub>L16800</sub>
|
||||
|
||||
### build graph, splat & the harness (115)
|
||||
### build graph, splat & the harness (117)
|
||||
|
||||
- **§4** — Flag/toolchain gotchas <sub>L190</sub>
|
||||
- **Build** — mechanism — per-file opt override (splat resegmentation) <sub>L288</sub>
|
||||
@@ -579,7 +587,9 @@
|
||||
- **§3-C2.** — RECONCILE BEFORE THE FIRST GATE — a parked draft gets HARDER to bank, not easier <sub>L17020</sub>
|
||||
- **§3-D.** — The measured cost shape, and what to build next <sub>L17043</sub>
|
||||
- **§176i** — WHAT A STATIC PRE-GATE CHECK CAN AND CANNOT PROVE (P31 S52, wave Q) <sub>L17061</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17289</sub>
|
||||
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17289</sub>
|
||||
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17585</sub>
|
||||
|
||||
### process, measurement & doctrine (79)
|
||||
|
||||
@@ -660,10 +670,10 @@
|
||||
- **§176h** — THE BATCH-SUBSTITUTION HAZARD MAP (P31 S52): seven holes, three wrong fixes, one law <sub>L16965</sub>
|
||||
- **§3-D.** — The measured cost shape, and what to build next <sub>L17043</sub>
|
||||
- **§176j-2** — THE REPAIR PASS, MEASURED (do this instead of resuming) <sub>L17119</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17370</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17422</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17718</sub>
|
||||
|
||||
### (unbucketed — title matched no symptom vocabulary) (183)
|
||||
### (unbucketed — title matched no symptom vocabulary) (188)
|
||||
|
||||
- **§3-How** — to use this <sub>L30</sub>
|
||||
- **§1** — Idiom catalog (asm pattern → C that produces it) <sub>L39</sub>
|
||||
@@ -846,8 +856,13 @@
|
||||
- **§3-A.** — THE `$0`-ADD OPAQUE COPY defeats `make_regs_eqv` (func_80033398, 93 ins) <sub>L17214</sub>
|
||||
- **§3-C.** — SINGLE-SET TEMPS GET THE BIRTHING BOOST (func_8001D3FC, 196 ins) <sub>L17243</sub>
|
||||
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17258</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17444</sub>
|
||||
- **What** — is NOT banked here <sub>L17461</sub>
|
||||
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17348</sub>
|
||||
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17398</sub>
|
||||
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17449</sub>
|
||||
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17545</sub>
|
||||
- **Considered** — and NOT banked <sub>L17568</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17740</sub>
|
||||
- **What** — is NOT banked here <sub>L17757</sub>
|
||||
|
||||
|
||||
## All sections, in order
|
||||
@@ -1397,12 +1412,22 @@
|
||||
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17258</sub>
|
||||
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17267</sub>
|
||||
- **§3-G.** — TWO MODELLING TRAPS THAT COST THESE AGENTS SWEEPS OF HUNDREDS OF COMPILES <sub>L17273</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17289</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17300</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17306</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17330</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17370</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17396</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17422</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17444</sub>
|
||||
- **What** — is NOT banked here <sub>L17461</sub>
|
||||
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17289</sub>
|
||||
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
|
||||
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17348</sub>
|
||||
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17398</sub>
|
||||
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17449</sub>
|
||||
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
|
||||
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
|
||||
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
|
||||
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17545</sub>
|
||||
- **Considered** — and NOT banked <sub>L17568</sub>
|
||||
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17585</sub>
|
||||
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17596</sub>
|
||||
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
|
||||
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
|
||||
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
|
||||
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17692</sub>
|
||||
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17718</sub>
|
||||
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17740</sub>
|
||||
- **What** — is NOT banked here <sub>L17757</sub>
|
||||
|
||||
@@ -17286,6 +17286,302 @@ scheduling decision, not cosmetics.
|
||||
fully DAG-determined. When order does not matter, the answer is an *alias* or a *set-count*
|
||||
property, not a permutation.
|
||||
|
||||
## §179 — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass)
|
||||
|
||||
Twelve readers mined the wave-P and wave-Q agent journals; 16 candidate findings survived their
|
||||
novelty filter, and merging duplicates + dropping what §174–§178 already own leaves the **eight
|
||||
levers below**. Every gcc/tool citation here was re-read against `tools/reference/gcc-2.7.2/`,
|
||||
`tools/maspsx/`, and `tools/masked_diff.py` in this pass — three line numbers were wrong in the raw
|
||||
findings and are corrected inline (marked ⚠). Ordered by how many functions each unblocks.
|
||||
|
||||
---
|
||||
|
||||
### §179-A — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs)
|
||||
|
||||
**Symptom.** A NEAR whose only residual is a register rotation around a pointer loop: the draft has
|
||||
a spurious `move $tN,$aM` that the target does not, the offset-K access lands on the *argument*
|
||||
register `$aM`, and the base cursor lands on a scratch temp — the exact mirror image of the target's
|
||||
allocation. `cc1 -dg` shows the argument register in the conflict set of the cursor pseudo
|
||||
(`N conflicts: … 7`, `M preferences: 7` for the `$a3` cases).
|
||||
|
||||
**Mechanism** (all lines re-read and confirmed). When a pointer **parameter** is used undecorated as
|
||||
a loop's biv *and* the loop also touches a fixed offset off that same pointer (so gcc mints a giv),
|
||||
`record_initial` (`loop.c:6327`) records the biv's defining insn — which is `assign_parms`' own
|
||||
incoming-argument copy `(set P (reg $aN))` — as `bl->init_set`. At `loop.c:3500` `src =
|
||||
SET_SRC (bl->init_set)` is therefore the **hard register** itself; `valid_initial_value_p`
|
||||
(`loop.c:4120`, called at `loop.c:3509`) accepts it, since it returns 1 for `CONSTANT_P` or any
|
||||
`GET_CODE == REG` (hard regs pass its `REGNO < max_reg_before_loop` test), given no intervening
|
||||
call. `bl->initial_value = src` (`loop.c:3511`). Then `emit_iv_add_mult (bl->initial_value, …,
|
||||
loop_start)` (`loop.c:3879`) emits the giv's preheader init as `new_giv = $aN + K` — **a fresh
|
||||
reference to the hard register, inserted after P's own copy-from-`$aN`**. That extends `$aN`'s live
|
||||
range past where P's copy would have let it die, `$aN` and P become simultaneously live, P loses the
|
||||
hard-reg tie, the giv inherits `$aN`, and the dead `move` survives.
|
||||
|
||||
**C lever — two spellings, both zero-byte, pick either:**
|
||||
```c
|
||||
/* 1. body-local copy: rename the parameter, route EVERY in-loop access through the copy */
|
||||
void f(T *param0, …) { T *p = param0; for (…) { … p->fld … p++; } }
|
||||
|
||||
/* 2. identity re-tie, placed in the preheader BELOW the n!=0 guard so it can't eat the
|
||||
guard branch's delay slot */
|
||||
if (n) { __asm__("" : "=r"(p) : "0"(p)); do { … } while (--n); }
|
||||
```
|
||||
Spelling 2 works by the *defeat* route: the init insn's `SET_SRC` becomes an `ASM_OPERANDS` rtx,
|
||||
which is neither `CONSTANT_P` nor `GET_CODE == REG`, so `valid_initial_value_p` returns 0,
|
||||
`bl->initial_value` falls back to the freely-allocatable pseudo, and `$aN` is released.
|
||||
|
||||
**Evidence (all MATCH).** `func_800262D8` (144→143, dead `move t1,a3` removed), `func_8002528C`,
|
||||
`func_80025000` (164/154-wrong → 163/4-wrong from this lever alone), `GsTMDfastF3GL`,
|
||||
`func_80025EB8`, `func_80025A30` (re-tie spelling), `func_80025504` (197 ins, poly pointer vs `$a3`),
|
||||
`func_80024DE8` (134/134, `-dg` confirmed the `$a3` conflict), `func_80025818`.
|
||||
|
||||
**Relationship to §70 (L5639) — read this before applying.** §70 documents the *same* chain used in
|
||||
the **opposite direction**: when the target wants the giv based on the argument register, walk the
|
||||
parameter directly and do **not** copy it. §179-A is the mirror. Decide by what the target's giv is
|
||||
based on, then choose: raw parameter (§70) vs. local copy / re-tie (§179-A).
|
||||
*Honest limit:* why a second-level copy does not simply recreate the identical chain one level
|
||||
removed was not re-derived from `assign_parms`' pseudo lowering; it rests on the source-verified
|
||||
general mechanism plus nine consistent byte-proofs.
|
||||
|
||||
---
|
||||
|
||||
### §179-B — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs)
|
||||
|
||||
**Symptom.** A splat-flagged handwritten / PsyQ LIBGS routine transcribed as inline asm comes out
|
||||
+N instructions (LENGTH-DRIFT), or the build dies with `MASPSX FAIL: invalid literal for int() with
|
||||
base 10: '0x18'`, or `masked_diff` reports a huge mismatch on a body you copied verbatim.
|
||||
|
||||
**Five rules, each source-verified, each a byte-miss or a crash if violated:**
|
||||
|
||||
1. **`.set` directives need a literal TAB.** `maspsx/__init__.py:844-848` is
|
||||
`elif line.startswith(".set\t"): if line.endswith("\tnoreorder"): self.is_reorder = False; elif
|
||||
line.endswith("\treorder"): self.is_reorder = True`. A space-separated `.set noreorder` matches
|
||||
neither test, is forwarded to `as` unchanged, and leaves maspsx's tracker at its default `True` —
|
||||
after which it auto-appends `nop # DEBUG: branch/jump` after **every** branch/jump it emits
|
||||
(`:1054-1057`, gated on `is_reorder`), clobbering your hand-filled delay slots. Write
|
||||
`".set\tnoreorder\n"`.
|
||||
2. **`.ent` does NOT update maspsx's state.** `:856-859` appends `.set\tnoreorder` to the *output*
|
||||
stream but never touches `self.is_reorder`. Never rely on it; write your own tab-formed directive.
|
||||
3. **Every displacement and immediate in DECIMAL.** `:970` and `:1038` both call bare `int(operand)`
|
||||
(base-10 default) on the raw offset string *before* the magnitude comparison short-circuits, so
|
||||
`lw $2,0x18($3)` throws `ValueError` regardless of range. Write `lw $2,24($3)`. (`.word`
|
||||
constants are unaffected and may stay hex.)
|
||||
4. **maspsx's LOAD-delay nop is UNCONDITIONAL — do not write it yourself.**
|
||||
`_handle_nop_before_next_instruction` (`:642-675`, called from `:908,931,964,991,1137,1181`)
|
||||
contains **no** `is_reorder` reference anywhere in its body or call sites — unlike the
|
||||
branch-delay path, which is explicitly gated. So even inside `.set\tnoreorder`, a `lw $v0,56($t1)`
|
||||
followed by a consumer of `$v0` still gets maspsx's own nop spliced in. This is the asymmetry
|
||||
that bites: **you manage branch-delay nops yourself; you must NOT manage load-delay nops.**
|
||||
5. **Prefix internal labels with `.L`.** `masked_diff.py:34` is
|
||||
`_HDR_RE = re.compile(r"^[0-9a-f]+ <([^>]+)>:")`, and `insns_from_object`'s collection loop
|
||||
(`:141-146`) sets `infn = (fn is None) or (h.group(1) == fn)` on **every** objdump `<label>:`
|
||||
header. A plain `sel_C94:` becomes a real symtab entry that objdump prints mid-function, flipping
|
||||
`infn` to False and silently truncating the rest of the function from the diff — a spurious
|
||||
byte-mismatch with no codegen cause. Write `.Lsel_C94:`.
|
||||
|
||||
**⚠ Conflict with the already-banked trampoline rules (L1848-1858).** That entry's rule 2 says *"no
|
||||
trailing `.set reorder` — it emits a stray epilogue nop."* The wave-P/Q GTE bodies found the
|
||||
opposite: close with a tab-formed `".set\treorder\n"` as the **last** asm line so maspsx restores
|
||||
its default and supplies the one nop gcc's auto-generated `jr $ra` epilogue needs. **Resolution:**
|
||||
the trampoline's body ends in a real instruction gcc's epilogue can use, the GTE bodies do not. If
|
||||
you are ±1 nop at the very end, flip this one lever and re-gate; it is the cheapest A/B in the file.
|
||||
|
||||
**Evidence (all MATCH).** `func_80027200` (133→125 via rules 1+3), `func_80025CBC` (127 ins,
|
||||
first-pass), `GsTMDfastF4GL` (162/162, 648/648 raw bytes), `GsTMDfastG3GL` (624/624 raw bytes),
|
||||
`GsTMDfastF3GL` (129/129 words), `GsTMDfastG4GL` (rule 4: hand-written nop gave 155/156 LENGTH-DRIFT
|
||||
−1; omitting it gave 156 + 624/624 bytes), `func_8005D8B4` (43→3 mismatched), `func_80059760`,
|
||||
`func_80059234`, `MoveImage`. The mechanism is also embedded as a code comment at
|
||||
`src/800b2.c:491-500`.
|
||||
|
||||
---
|
||||
|
||||
### §179-C — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__`
|
||||
|
||||
**Symptom.** The target's disassembly for a symbol has **zero trailing `jr $ra`** — it ends
|
||||
mid-basic-block, or every exit is a raw unlinked `j SOME_OTHER_LABEL` with live values in argument
|
||||
registers, and the immediately-following symbol is nothing but a `lw $ra / addiu $sp / jr $ra` tail
|
||||
restoring *this* function's frame offsets. Every C shape you try comes out exactly +2 instructions
|
||||
(a phantom `jr $ra` / `nop`).
|
||||
|
||||
**Mechanism.** gcc-2.7.2 has **no sibcall / cross-function tail-merge pass** (absent from the pinned
|
||||
`config/mips/mips.c`), and every function whose body cc1 compiles goes through normal function-exit
|
||||
expansion (`function.c:5224 expand_function_end`, return emission at `:5432-5437`) with
|
||||
`function_epilogue` (`mips.c:5072`) emitting the teardown text at final time. `noreturn`, a bare
|
||||
tail `j`, and a function-body `__asm__ __volatile__` all fail to suppress it — the append is a
|
||||
property of the enclosing C function, not of the asm's RTL.
|
||||
|
||||
**C lever.** Write the whole thing as **top-level** (file-scope) basic asm, outside any C function,
|
||||
carrying its own directives — cc1 never runs function-expansion over it:
|
||||
```c
|
||||
__asm__(".text\n.align 2\n.globl NAME\n.ent\tNAME\n"
|
||||
"NAME:\n.frame $sp,N,$31\n.mask MASK,-8\n.fmask 0,0\n"
|
||||
".set\tnoreorder\n"
|
||||
"<body, decimal offsets, .L labels>\n"
|
||||
".set\treorder\n.end\tNAME\n");
|
||||
```
|
||||
Three sub-rules: (a) use **literal** `.ent\t` / `.end\t` text — `glabel` (`include/labels.inc:7`,
|
||||
`include/macro.inc:10`) is an assembler `.macro`, expanded by `as` *after* maspsx runs, so maspsx
|
||||
never sees `.ent` and leaves reorder mode on, scrambling your delay slots; (b) in file-scope asm `%`
|
||||
is literal, so write `%hi`/`%lo` **un-doubled** (the `%%hi` escaping of L1858 applies only to
|
||||
function-body operand-template asm); (c) if the *following* symbol is the shared tail, emit a second
|
||||
real `.ent <nextsym>` / label / `.end <nextsym>` immediately after this function's `.end` — the
|
||||
harness's objdump-header boundary walk (§179-B rule 5, same `_HDR_RE`) then attributes exactly the
|
||||
target's instruction count to each symbol. That is the same tooling fact used deliberately instead
|
||||
of tripped over.
|
||||
|
||||
**Bonus: raw `.word` bodies.** When mnemonic transcription is hostile, a straight list of
|
||||
`.word 0xHHHHHHHH` copied from the target's own words works — but **stop the list before the
|
||||
target's own closing `jr $ra`/`nop`**: gcc supplies the frameless-leaf epilogue itself, so including
|
||||
them is +2. (`GsTMDfastF4GL`: all 162 words → LENGTH-DRIFT +2; words [0..159] → MATCH at 162 ins,
|
||||
648/648 bytes.)
|
||||
|
||||
**Evidence.** `func_80059234` (71/71 real target instructions; a function-body `noreturn` asm left 2
|
||||
dead trailing instructions, a `glabel`-based file-scope attempt produced a garbled 79-ins object),
|
||||
`func_80059FC0` (MATCH, size 0xA8, two raw `j SYS_OBJ_E34` tails with `$v0`/`$v1` live-out and no
|
||||
`$s0-$s3`/`$ra` restore), `MoveImage` (42/42, closeness 0; all 7 referenced symbols verified against
|
||||
the target's own relocation lines).
|
||||
**Follow-up worth a pass:** `func_8005BD7C`, `func_8005C1C0`, `SetGraphReverse` are all NEAR in the
|
||||
same slice and all diagnose this exact root cause without finding the fix. They are likely
|
||||
re-crackable with §179-C verbatim.
|
||||
|
||||
---
|
||||
|
||||
### §179-D — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE
|
||||
|
||||
**Symptom.** The draft uses `$t4-$t8` where the target uses `$t5-$t9` — a clean one-slot shift of the
|
||||
*entire* temp register file. Tell: **the target never uses `$t4` even though `$t4` appears in the
|
||||
`cfc2`.**
|
||||
|
||||
**Mechanism.** `gte_stflg` reads the GTE FLAG register with a `cfc2` hardwired to physical `$12`
|
||||
(= `$t4` in the o32/PSX ABI), outside its declared operands. With `"$12"` missing from the clobber
|
||||
list, gcc treats `$t4` as allocatable, parks a live pseudo (a loop counter, in both exemplars)
|
||||
there, and the `cfc2` destroys it — and the allocation order cascades from that point, shifting
|
||||
every later temp.
|
||||
|
||||
**C lever.** Any inline-asm / raw-`.word` GTE macro that writes a fixed physical COP2-adjacent
|
||||
register outside its operands must list it **by number** in the clobber list: `: "$12"`.
|
||||
|
||||
**Evidence.** `func_80025504` (MATCH, 197 ins — counter had been placed in `$t4`), `func_80024DE8`
|
||||
(MATCH, 134/134). No gcc-source claim is made here; this is byte-evidence + ABI.
|
||||
|
||||
---
|
||||
|
||||
### §179-E — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP
|
||||
|
||||
**Symptom.** The target shows `[compute end address] + [loop: 4-word load/store group, compare,
|
||||
branch] + [straight-line leftover load/store group]`. Element-by-element `for` loops and
|
||||
hand-unrolled pointer-diff variants regress to 54–64 instructions with garbled 2-word sub-splits.
|
||||
|
||||
**Mechanism.** `mips.c:2216-2217` defines `MAX_MOVE_REGS 4` / `MAX_MOVE_BYTES (MAX_MOVE_REGS *
|
||||
UNITS_PER_WORD)`. `expand_block_move` (`mips.c:2331`) dispatches any compile-time-constant,
|
||||
word-aligned BLKmode copy larger than `2*MAX_MOVE_BYTES` to `block_move_loop` (`mips.c:2222`, which
|
||||
`abort()`s below that size at `:2237`). It computes `leftover = bytes % MAX_MOVE_BYTES` (`:2240`),
|
||||
emits **one** `movstrsi_internal`-driven loop with a computed end-address compare/branch, then a
|
||||
single straight-line `movstrsi_internal` for the leftover (`:2286-2289`). This is a *different* path
|
||||
from the already-banked ≤`2*MAX_MOVE_BYTES` single-shot case (L2428) and the -O0 `memcpy`
|
||||
library-call case (L2531). `unroll.c` is dead at -O2, so no hand loop reproduces it.
|
||||
|
||||
**C lever.**
|
||||
```c
|
||||
typedef struct { s32 words[N]; } BlkNN; /* N sized to the exact byte count */
|
||||
extern BlkNN SRC, DST;
|
||||
void f(void) { BlkNN buf; buf = SRC; DST = buf; }
|
||||
```
|
||||
|
||||
**Evidence.** `func_80029274` → MATCH (42/42) after the struct rewrite.
|
||||
|
||||
---
|
||||
|
||||
### §179-F — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION
|
||||
|
||||
**Symptom.** The target keeps a walked pointer as a single un-combined biv (`addiu $s0,$s0,0x54`
|
||||
plus full literal field offsets at every access), and every C-source-order trick and asm fence still
|
||||
lets gcc split it into two givs.
|
||||
|
||||
**Mechanism.** loop.c's IV machinery considers **pseudos only**. The biv scan requires
|
||||
`REGNO (dest_reg) >= FIRST_PSEUDO_REGISTER` before calling `basic_induction_var` (`loop.c:3301`),
|
||||
and the giv-collection loop does `if (REGNO (dest_reg) < FIRST_PSEUDO_REGISTER) continue;`
|
||||
(⚠ **`loop.c:3572-3573`**, not `:3571` as the raw finding claimed — `:3571` is the `dest_reg =
|
||||
SET_DEST (set);` above it). So a hard-register pin makes the pointer **categorically invisible** to
|
||||
`combine_givs`/strength-reduction, not merely de-prioritized. This is strictly stronger than the
|
||||
banked zero-byte-asm anti-dissolution launderers (L2483), which only perturb the benefit heuristic.
|
||||
|
||||
**C lever.** `register Ent *p __asm__("$16");` on the walked pointer — using the register the target
|
||||
actually uses.
|
||||
|
||||
**Evidence.** `func_8003324C` → MATCH (54/54). Ablation: without the pin, `p` splits into a `+0x2A0`
|
||||
call-arg giv and a `+0x2EE` address giv → 58 ins / 44 mismatched; with it, back to the single
|
||||
`addiu $s0,$s0,0x54` walk.
|
||||
|
||||
---
|
||||
|
||||
### §179-G — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1)
|
||||
|
||||
**Symptom.** The target retains an `andi $sN,$fp,0xFFFF` narrowing mask; your draft folds it to a
|
||||
bare `move` and is one instruction short — and you currently have a pin on the mask's consumer.
|
||||
|
||||
**Mechanism.** combine's `LOG_LINKS` never cross basic blocks (already-banked law, L2489, `flow.c:2087`),
|
||||
so a `(u16)y` mask survives whenever `y`'s def and the `andi`'s consumer sit in different blocks —
|
||||
combine has nothing to hang a link on. A `register T x __asm__("$21")` pin inserts a **same-block
|
||||
hard-reg move**, which manufactures exactly that missing `LOG_LINK`; `nonzero_bits` reasoning then
|
||||
legally folds the `andi` away. Removing the pin removes the link and the `andi` returns.
|
||||
|
||||
**C lever.** When a target keeps a narrowing mask on a pinned value, **remove the pin first**, before
|
||||
anything else. This is a distinct causal channel from RC-5's four documented pin side effects
|
||||
(init-copy, `bad_spill_regs` poisoning, pass-0 availability shift, range blocking) and from the fifth
|
||||
(§164-49, pin-perturbs-scheduling) — all five of those are regalloc/sched1-shaped; this one runs
|
||||
through combine.
|
||||
|
||||
**Evidence.** `func_80032048` (152/152, MATCH): removing all three pins restored the `andi` and, with
|
||||
a separate u8→u32 widening fix, closed it.
|
||||
**⚠ Banked with a flag:** n=1, no independent A/B re-run, and **no exact `combine.c` line number
|
||||
exists for the pin→LOG_LINK creation claim itself** — I could not derive one in this pass. Treat as a
|
||||
strong heuristic, not settled law. Needs an exact citation + a second exemplar. (The neighbouring
|
||||
`set_nonzero_bits_and_sign_copies` law at L11075 / `combine.c:718-788` governs a related but
|
||||
different case — a multi-set, multi-block pseudo's nonzero-bits record.)
|
||||
|
||||
---
|
||||
|
||||
### §179-H — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE
|
||||
|
||||
**Symptom.** A symbol classified NEAR/FRAGMENT that is provably not a real function — the target `.s`
|
||||
shows no prologue, and a sibling's tail branches straight into it. Reconstructing the fragment alone
|
||||
won't compile (no incoming register state); reconstructing the whole enclosing routine means the
|
||||
non-fragment part must also be byte-exact, which it never is.
|
||||
|
||||
**C lever.** Write ONE C function that reconstructs enough of the enclosing routine to get the right
|
||||
live values into the right registers (`register T v __asm__("$N")` pins for every live-in), then drop
|
||||
`__asm__ volatile(".global TARGET\nTARGET:")` at the point corresponding to the real symbol's entry
|
||||
address and a matching `_END` label at its exit. `match_one`'s `insns_from_object` slices the object
|
||||
between symbol labels, so **only that slice must be byte-exact** and the setup code is exempt.
|
||||
Terminate the fragment's own exit with a raw `__asm__ volatile("j OTHER_FUNC")` — **not** a C call —
|
||||
so gcc does not grow an `$ra`/`$sN` save/restore frame around a region whose real frame is owned by
|
||||
the unreconstructed caller.
|
||||
|
||||
**Evidence.** `SYS_OBJ_26EC` → MATCH (47 ins), construction confirmed by reading
|
||||
`.run/wave_p31q/main/SYS_OBJ_26EC.c` directly. The journal notes this is the "same technique as
|
||||
`SYS_OBJ_1DC0.c`" — i.e. it was used at least once before and never fed back into the cookbook, which
|
||||
is the gap this entry closes. No source-level citation; the claim rests on the byte-diff.
|
||||
|
||||
---
|
||||
|
||||
## Considered and NOT banked
|
||||
|
||||
| Rejected | Why |
|
||||
|---|---|
|
||||
| **§70's "walk the parameter directly" direction** (L5639) | Already banked. Kept only as the explicit contrast note inside §179-A, which is its mirror — a future agent needs both directions side by side to choose. |
|
||||
| **`__asm__ __volatile__("" ::: "memory")` as a CSE defeat** | Already banked at L1816-1819 (§21) and L13300, and §178-G2 already warns it is a *full* barrier. Deliberately stripped from the §179-H lever description. |
|
||||
| **`"=r"(x) : "0"(x)` as an address-rematerialisation launder** | Already banked near-verbatim as §153 (L10463, "THE ADDRESS-REMATERIALISATION LAUNDER"). Note: §179-A uses the *same instrument* against a *different governing predicate* (`valid_initial_value_p`, not cse's `qty_const`), so only that new application is banked. |
|
||||
| **≤`2*MAX_MOVE_BYTES` single `movstrsi_internal` copies; -O0 `memcpy` library call** | Already banked at L2428 and L2531. §179-E covers only the `>2*MAX_MOVE_BYTES` loop-with-remainder shape. |
|
||||
| **The trampoline's three maspsx rules** (no nop after `jal`; `%%hi`/`%%lo` escaping; no trailing `.set reorder`) | Already banked at L1848-1858. The third one is *contradicted* by wave P/Q, so §179-B carries the conflict-resolution note rather than a restatement. |
|
||||
| **maspsx "forces noreorder per function"** (the `func_80185B44` vetting note, `__init__.py:857-859`) | Already banked — but it is *misleading on its own*, since `.ent` does not update `self.is_reorder`. §179-B rule 2 corrects it rather than re-banking it. |
|
||||
| **Everything in §174–§178 and §176a–§176j** | Excluded by instruction: PsyQ names, `match_one` relocation masking, statement order around a call, pins-cannot-cross-a-call, declaration form as a scheduling lever, the `$0`-add opaque copy, return-const priority, `birthing_insn_p`, narrow-type copy elision, the zero-offset alias hole, `MEM_IN_STRUCT_P`, `mips_epilogue_delay_slots`. Several readers surfaced near-restatements of these; all dropped. |
|
||||
| **§177's epilogue return-delay-slot class** (`mips.c:5376`, L17156) | Adjacent but genuinely different: that is a *within-function* scheduling gate steerable by callee-saved count. §179-C is a *cross-function* frame-sharing phenomenon with no compiler pass involved at all. Both kept, neither merged. |
|
||||
| **The raw findings' `loop.c:3571` giv-skip citation** | ⚠ **Corrected**, not dropped — the test is at `:3572-3573`. |
|
||||
| **The raw findings' `loop.c:3499` `SET_SRC` citation** | ⚠ **Corrected** to `:3500` (the `valid_initial_value_p` call at `:3509` and `bl->initial_value = src` at `:3511` both check out exactly). |
|
||||
| **"`func_8005A9FC0`"** | ⚠ Typo in the raw finding; the real symbol is `func_80059FC0` (confirmed from the draft path and `asm/nonmatchings/800c/func_80059FC0.s`). Banked under the correct name in §179-C. |
|
||||
| **"`expand_function_end` unconditionally appends, with no `noreturn` guard"** | Softened. `function.c:5224` and the return emission at `:5432-5437` are confirmed present, and `function_epilogue` (`mips.c:5072`) is the final-time emitter — but the "no guard anywhere on the path" claim was not traced line-by-line. §179-C states the observable (three byte-proofs) and cites the location, not a derived proof. |
|
||||
|
||||
## §176c — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY
|
||||
|
||||
main's `make extract` runs the EXE-only `psyq_integrate` + `ld_interleave` steps, which **rewrite the
|
||||
|
||||
Reference in New Issue
Block a user