From 932977cc5a8a16e970a26f9be68b10a680b070b0 Mon Sep 17 00:00:00 2001
From: Drew T <50529377+Druthulu@users.noreply.github.com>
Date: Mon, 31 Aug 2026 14:27:10 -0600
Subject: [PATCH] =?UTF-8?q?docs(cookbook):=20=C2=A7348=20base=20spelling?=
=?UTF-8?q?=20picks=20the=20addressing=20mode=20(3-insn=20lui/%lo=20vs=202?=
=?UTF-8?q?-insn=20addu/lw);=20=C2=A7137=20refuted=20on=20constants?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/cookbook-index.md | 7 +++++--
docs/matching-cookbook.md | 17 +++++++++++++++++
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md
index 263f6769c..81ce7e5b5 100644
--- a/docs/cookbook-index.md
+++ b/docs/cookbook-index.md
@@ -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 / 998 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 / 999 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.
@@ -340,7 +340,7 @@
- **§328** — THE VOLATILE ALIAS MUST BE AN *OBJECT*, NOT A CAST: `*(volatile s32*)&sym` UNFOLDS %lo INTO A SEPARATE `addiu` (P31 S67; byte-proven ov_SC07_007/func_80181B8C, 156 ins, NEW LAW) L31024
- **§345** — A VOLATILE **STORE** EVICTS THE MEM FROM cse AND KEEPS `sh`; A VOLATILE **LOAD** BLOCKS combine AND DEGRADES `lh` INTO `lhu+sll+sra` (P31 S67; byte-proven ov_SC01_084/func_80181A7C) L31312
-### loops & induction variables (37)
+### loops & induction variables (38)
- **§3-T1** — Loop pointer: top-of-body for `addu` induction, not constant-folded `addiu` L71
- **§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) L2473
@@ -379,6 +379,7 @@
- **§344** — RAISE A BIV'S global_alloc PRIORITY WITH A ZERO-BYTE REFERENCE INSTEAD OF PINNING IT; PINNING THE COUNTER KILLS LSR ENTIRELY (P31 S67; byte-proven ov_SC03_121/func_80180E64, 222 ins) L31296
- **§346** — `c ? X : -X` TAKES expand_expr's COND_EXPR **SINGLETON** PATH (copy, then negate IN PLACE) — AN if/else STATEMENT GIVES THE TWO-ARM FORM (P31 S67; byte-proven ov_SC03_102/func_80180C38, closed the last instruction) L31322
- **§347** — LOOP REGISTER ASSIGNMENT IS A **DECLARATION-ORDER + LIVE-RANGE** DIAL: FIVE COMPOSABLE LEVERS, 178 -> 0 (P31 S67; byte-proven ov_SC06_029/func_8017EF34, 243 ins) L31342
+- **§348** — THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A POINTER VARIABLE GIVES THE 2-INSN `addu/lw` FORM (P31 S67; byte-proven ov_SC07_007/func_80182184, 264 -> 30 on this row alone) L31397
### structs, block moves & memcpy (80)
@@ -2537,6 +2538,7 @@
- **§347** — LOOP REGISTER ASSIGNMENT IS A **DECLARATION-ORDER + LIVE-RANGE** DIAL: FIVE COMPOSABLE LEVERS, 178 -> 0 (P31 S67; byte-proven ov_SC06_029/func_8017EF34, 243 ins) L31342
- **§347-addendum** — A THIRD INSTANCE, AND THE SHARPEST STATEMENT OF THE RULE (md_MAIN_025/func_800CB300, 243 ins) L31372
- **§343-addendum** — SECOND INSTANCE OF THE WRONG-MAJORITY DECL (same function) L31390
+- **§348** — THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A POINTER VARIABLE GIVES THE 2-INSN `addu/lw` FORM (P31 S67; byte-proven ov_SC07_007/func_80182184, 264 -> 30 on this row alone) L31397
---
@@ -3547,3 +3549,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
| L31342 | §347 | LOOP REGISTER ASSIGNMENT IS A **DECLARATION-ORDER + LIVE-RANGE** DIAL: FIVE COMPOSABLE LEV |
| L31372 | §347-addendum | A THIRD INSTANCE, AND THE SHARPEST STATEMENT OF THE RULE (md_MAIN_025/func_800CB300, 243 i |
| L31390 | §343-addendum | SECOND INSTANCE OF THE WRONG-MAJORITY DECL (same function) |
+| L31397 | §348 | THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A P |
diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md
index 9033b68eb..26e0e8850 100644
--- a/docs/matching-cookbook.md
+++ b/docs/matching-cookbook.md
@@ -31393,3 +31393,20 @@ The switch bound is `sltiu`, so `func_801633A8` must return **u32** — while th
fleet row says `s32`. Same shape as §343: the corpus majority is a propagated spelling, and the
INSTRUCTION decides. An unsigned compare on the return value is direct evidence of an unsigned
return type.
+
+## §348 — THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A POINTER VARIABLE GIVES THE 2-INSN `addu/lw` FORM (P31 S67; byte-proven ov_SC07_007/func_80182184, 264 -> 30 on this row alone)
+
+For a repeated read off a base (an OT base here), how you SPELL the base decides the addressing mode
+gcc emits, and the two differ in length:
+
+ read via the SYMBOL -> lui / %lo / load (3 insns, the FIRST read)
+ read via a POINTER VARIABLE -> addu / lw (2 insns, every read after)
+
+So the target's mix of forms is telling you which reads went through the symbol and which through a
+held pointer. Matching that mix is a LENGTH fix, not a register fix — here it was the entire drift,
+264 → 30 in one change. Then ordinary §17/§325 pins closed the rest (30 → 15 → 0).
+
+**REFUTED on the same function, worth recording:** §137's zero-byte `"r"(K)` reference dial **does
+not work on constants** — cse will not fold the extra reference onto the existing constant pseudo,
+so every probe cost +1/+2 instructions. The §344 "add a reference to raise priority" trick applies to
+a biv or a live variable, NOT to a materialised constant.