From de141dc221e4ca977418076ef2f8cb6a5b1f26c8 Mon Sep 17 00:00:00 2001
From: Drew T <50529377+Druthulu@users.noreply.github.com>
Date: Wed, 5 Aug 2026 14:48:26 -0600
Subject: [PATCH] =?UTF-8?q?docs(phase-30=20S42):=20cookbook=20=C2=A7148=20?=
=?UTF-8?q?=E2=80=94=20the=20loop.c=20hoisting=20threshold=20arithmetic,?=
=?UTF-8?q?=20the=20MIN=5FEXPR=20clamp=20fold,=20the=20allocno-priority=20?=
=?UTF-8?q?slider;=20and=20the=20x16=20claim=20corrected?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/cookbook-index.md | 21 ++++++++---
docs/matching-cookbook.md | 77 +++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md
index 6698b659b..38ad29bc2 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 / 419 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 / 424 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.
@@ -41,7 +41,7 @@
- **§3-D.** — THE CROSS-JUMP RATCHET (the sharpest new trap — `func_80131340` L-C) L3501
- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058
-### instruction scheduling (16)
+### instruction scheduling (18)
- **§3-T2** — Source statement order drives instruction scheduling L78
- **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) L107
@@ -59,8 +59,10 @@
- **§3-The** — attribution primitive (use this before calling anything a scheduling residual) L6050
- **§3-The** — scheduling rules (refining §135-2 and §135-4) L8902
- **Consequence** — for the family (a real scheduling decision) L10085
+- **§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) L10098
+- **§3-A.** — `move_movables` hoists iff `threshold × savings × lifetime ≥ insn_count` — and you can read it L10104
-### register allocation & pins (35)
+### register allocation & pins (36)
- **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) L835
- **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register L856
@@ -97,13 +99,14 @@
- **§3-The** — same swallow, twice more, in the integration spine L9699
- **§3-B.** — A `?:` on MEMORY operands costs ~16 bytes of invisible frame; on REGISTER operands, zero L10047
- **§3-D.** — A lone `$t8`/`$t9` in the target is RELOAD SCRATCH — reproduce the spill, don't pin the register L10063
+- **§3-C.** — A zero-byte ALLOCNO-PRIORITY slider L10137
### CSE / redundancy / rematerialization (2)
- **§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) L3306
- **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom L6445
-### loops & induction variables (8)
+### loops & induction variables (9)
- **§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) L2447
@@ -113,6 +116,7 @@
- **§66d-1** — What transfers between giants is the LOOP, not the PIN L5273
- **§70** — The giv-init base register: walk the PARAMETER, not a copy of it (Phase 29 SESSION-18, `func_801777BC`) L5612
- **§145** — Three loop/combine levers from the S40 wave-2 drafters (16/16 match_one) L9917
+- **§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) L10098
### structs, block moves & memcpy (30)
@@ -563,7 +567,7 @@
- **§147** — The three-stratum FRAME LAW, and four "stop searching" verdicts (P30 S42, `func_8017C294`, serial run) L10026
- **§3-C.** — Inner-block declaration does NOT delay slot allocation — BYTE-REFUTED L10058
-### (unbucketed — title matched no symptom vocabulary) (120)
+### (unbucketed — title matched no symptom vocabulary) (122)
- **§3-How** — to use this L30
- **§1** — Idiom catalog (asm pattern → C that produces it) L39
@@ -685,6 +689,8 @@
- **§144** — THE LITERAL'S SPELLING PICKS THE IMMEDIATE ENCODING (P30 S40 wave 1, `func_801822E0`) L9878
- **§3-Why** — a correct draft can read as an intrinsic wall L9978
- **§3-The** — rule L10013
+- **§3-B.** — `(v < 0x40) ? v : 0x3F` is folded to `MIN_EXPR` and expands to the WRONG SHAPE L10123
+- **§3-D.** — Reproduce the original's BUGS verbatim L10147
## All sections, in order
@@ -1108,3 +1114,8 @@
- **§3-D.** — A lone `$t8`/`$t9` in the target is RELOAD SCRATCH — reproduce the spill, don't pin the register L10063
- **§3-E.** — A `qty_compare` TIE is not spelling-reachable — recognise it and stop L10073
- **Consequence** — for the family (a real scheduling decision) L10085
+- **§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) L10098
+- **§3-A.** — `move_movables` hoists iff `threshold × savings × lifetime ≥ insn_count` — and you can read it L10104
+- **§3-B.** — `(v < 0x40) ? v : 0x3F` is folded to `MIN_EXPR` and expands to the WRONG SHAPE L10123
+- **§3-C.** — A zero-byte ALLOCNO-PRIORITY slider L10137
+- **§3-D.** — Reproduce the original's BUGS verbatim L10147
diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md
index 1bed34c4f..39d5a48d5 100644
--- a/docs/matching-cookbook.md
+++ b/docs/matching-cookbook.md
@@ -10092,3 +10092,80 @@ all 16 in one pass.
**Symptom lines for the index:** **"a mystery stack slot at the top of the frame"** · **"frame is a
multiple of 16 too large"** · **"a lone $t8/$t9 in the target"** · **"exactly one register pair
transposed"** · **"permuter and hand-search plateau at the same number"**.
+
+---
+
+## §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)
+
+Serial run #2. Reached **NEAR(63)** of 947 (frame `0x120` exact, `vars=232` exact, all opcodes,
+immediates, stack offsets and branch targets correct; residual is one register rotation). Did not
+bank. The levers below are the yield.
+
+### A. `move_movables` hoists iff `threshold × savings × lifetime ≥ insn_count` — and you can read it
+
+`loop.c:1631` sets **`threshold = 58`** for this MIPS config and **decrements it by 3 per movable
+already moved** (`threshold -= 3`, loop.c:1719/1904). This is the first *quantitative* handle we have
+on gcc-2.7.2 invariant motion.
+
+Measured here: the draft's prim loop was **513** RTL insns, so `&g.flag` (savings 3, lifetime 3 →
+`58×3×3 = 522 ≥ 513`) got hoisted into a preheader register that the target recomputes **inline** —
+costing a callee-saved register and cascading into 2 extra spills and **+96 instructions**.
+Duplicating the `if (za < g.sz2) za = g.sz2;` tail into **both** arms of the `sz0>sz1` test (which the
+target's cross-jump reveals) pushed the loop to **523** insns → `522 < 523` → **not hoisted** → the
+register came back.
+
+**Symptom → lever:** an address (`&x`) hoisted into a loop-preheader register that the target
+recomputes inline ⇒ **raise the loop's RTL insn count by ~10, or lower the movable's ref count.**
+**Read it directly:** `cc1 -dL` writes `.i.loop`, which prints
+`Loop from A to B: N real insns` and, per movable, `Insn K: regno R (life L), savings S
+moved/not desirable`. Stop guessing which invariant moved — the dump names it.
+
+### B. `(v < 0x40) ? v : 0x3F` is folded to `MIN_EXPR` and expands to the WRONG SHAPE
+
+`fold-const.c:4948` — `A < C1 ? A : C2` with `C1 == C2+1` becomes `MIN(A,C2)`, which expands as
+**copy-then-conditionally-overwrite** (`move t,v; slti; bnez; li`). `A <= C ? A : C` folds too (the
+`A op B ? A : B` rule at 4907).
+
+ (v < 0x40) ? v : 0x3F -> MIN_EXPR -> move/slti/bnez/li WRONG
+ (v > 0x3F) ? 0x3F : v -> no fold -> jumpifnot/store/j/store RIGHT
+
+Same `slti $v0,$v,0x40` is emitted either way — but the second keeps gcc's canonical branchy form.
+**This single respelling took the draft from close 827 to close 63 and fixed all four clamps
+instruction-for-instruction.** Corollary: `(v < 0) ? 0 : X` is safe — fold's "swap if arg1 is simpler"
+rewrites it to `(v >= 0) ? X : 0`, which is exactly the target's `bltz`.
+
+### C. A zero-byte ALLOCNO-PRIORITY slider
+
+ __asm__ ("" :: "r"(a), "r"(b)); /* emits nothing */
+
+Priority is `floor_log2(n_refs)·n_refs·size / live_length`, and `REG_N_REFS` is incremented **by loop
+depth** — so an empty asm with `"r"` inputs inside a loop adds `depth` references per operand while
+emitting **no code**. Used here it flipped `{rowptr,y}` ↔ `{cx1,cy1}` for the last two callee-saved
+registers. **This is the counterpart to §47's live-length slider: that one moves the DENOMINATOR,
+this one moves the NUMERATOR.**
+
+### D. Reproduce the original's BUGS verbatim
+
+This variant's F3 arm bbox-tests the packet through **PolyFT3** offsets (pkt+8/+0x10/+0x18, stride 8)
+while writing F3 xy at stride 4; the FT4 arm reads `tmpxy[3].vx` where `.vy` is meant. Both are
+original-source copy/paste bugs. Matching means reproducing them.
+
+### ⚠️ E. A "these are all the same function" claim needs the DRAFT test, not a diff
+
+The run reported all sixteen 947-ins instances as one identical body (→ "one crack banks 15,152 ins").
+**Checked and it does not hold:** the draft scores **63** on `ov_SC03_126` but **340** on
+`func_8017C59C` and `func_8017CF90` — with an *identical* first diff on both, i.e. those two match
+each other but not the cracked one. That is consistent with the h_norm clustering (947×3, 947×2, plus
+singletons): **several multi-instance groups, not one group of 16.** A normalized-stream diff can say
+"same shape"; only *running the actual draft against the sibling's asm* says "same body". **Cheap
+test, do it before scaling a ×N claim** (`sed s/func_A/func_B/` the draft and `match_one` it).
+
+### Tooling note
+
+`permuter_ils` cannot be aimed at this draft: `run_masked` reports *"Function … not found in
+base.c"* because the `gte_*` `#define` block defeats `make_base_c`. **Demacroize first** — worth doing
+generally, since any GTE-using draft hits it.
+
+**Symptom lines for the index:** **"an &address hoisted into a loop preheader"** · **"a clamp expands
+as move-then-overwrite"** · **"MIN_EXPR"** · **"two callee-saved registers swapped"** · **"permuter
+says function not found in base.c"**.