From f83443ecdcf7b8b68efb65f31d1c0468972adce2 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Tue, 1 Sep 2026 23:19:52 -0600 Subject: [PATCH] =?UTF-8?q?docs(cookbook):=20=C2=A7405=20the=20S70=20wave?= =?UTF-8?q?=20harvest=20(113=20MATCH=20/=20130=20agents)=20+=20=C2=A7406?= =?UTF-8?q?=20the=20134-function=20prologue-weave=20sweep?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §405 — the generalisable residue of three waves, grouped by lever family: A. match_one compares .text ONLY, so a switch's jump table is invisible to it — a draft can score 110/110 with a PERMUTED table emitted as identity (resident/func_800D02D0, byte-witnessed). Some historical 'MATCH but gate rejected' verdicts were the ORACLE being wrong (R34 in our most-trusted tool). B. the scheduler dials, incl. the birthing-boost re-tie's PLACEMENT rule (must be a LATER basic block) and reorg's stop_search_p halting at any asm. C. regalloc from C without pins: variable identity picks global- vs local-alloc; a cross-arm join value loses first-fit and should be duplicated per arm for cross_jump to refund; pass-through params reserve arg regs at zero cost. D. integration is still the bottleneck — ~1/3 had byte-correct bodies blocked only by declarations; the TU is the authority. E. what the agents REFUTED: §137 invariance is false for CONFLICT-driven ties; §153's 'cse2 puts it back' fails for the dead-def case; §257-8 volatility polarity is per-site, not portable. §406 — the prologue-weave class: 134 of 1,237 open stubs (11%) share the sw / move , / sw shape, cause traced in cc1's .i.sched2 dump (memrefs_conflict_p finds no dependence, potential_hazard picks sw $ra early), 12 variants measured inert, and ONE working lever (non-volatile memory-clobber asm after the param copy). One lever x 134 known targets = a sweep, not an idiom. --- docs/cookbook-index.md | 41 ++++++++++++++---- docs/matching-cookbook.md | 88 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index f03f030a1..85f25b1c5 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 / 1066 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 / 1073 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) L31838 - **§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) L32818 -### instruction scheduling (85) +### instruction scheduling (86) - **§3-T2** — Source statement order drives instruction scheduling L78 - **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) L107 @@ -189,8 +189,9 @@ - **§381** — THE `insn_count` HOIST THRESHOLD IS A DIAL YOU CAN READ WITH `cc1 -dL` (P31 S69; four independent uses in one wave) L32216 - **§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) L32309 - **§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) L32543 +- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) L33108 -### register allocation & pins (127) +### register allocation & pins (128) - **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) L854 - **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register L875 @@ -319,6 +320,7 @@ - **§3-2.** — A REGISTER PIN THAT DELETES A sched2 ANTI-DEPENDENCE L31997 - **§374** — A `register … __asm__("$30")` RESERVATION IS **NOT HONOURED** BY `move_movables` (P31 S68; main/func_80015608, 86 ins) L32026 - **§375** — AN `$a0`-`$a3` PIN USED LATE RELOCATES AN **EARLIER** OUTGOING-CALL USE OF THAT REGISTER (P31 S68; main/func_8005F0C8, 88 ins) L32042 +- **§3-C.** — REGISTER ALLOCATION FROM C, WITHOUT PINS L33124 ### CSE / redundancy / rematerialization (44) @@ -717,7 +719,7 @@ - **§378c** — ★★ — THE FIFTH DECL-BLOCKER VARIANT: THE DRAFT REDECLARES WHAT THE TU ALREADY OWNS (P31 S69) L32722 - **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) L32835 -### jump tables & switches (56) +### jump tables & switches (57) - **§8** — rodata island (compiler jump tables) — the `.data→.rodata→.data` sandwich (Phase 7) L339 - **§8a** — rodata island in a flat OVERLAY — the tail sandwich, per matched jr-function (Phase 26 — PoC PROVEN) L361 @@ -775,6 +777,7 @@ - **§384** — ★★★ — A CARVE-CONFIG BANK IS RED UNTIL YOU RE-EXTRACT, AND THAT LOOKS EXACTLY LIKE A FALSE BANK (P31 S69; measured twice, cost one destroyed match) L32259 - **§387** — ★★ — **SPLIT-FOLD DISPATCH CLOBBER**: one switch case needs a reload, another must keep the fold (P31 S69; byte-proven main/func_80030F80, 343 ins, escalation 3 → 0) L32361 - **§322b** — ★★★ — THE CARVE CLASS IS COMPLETABLE, AND EVERY WORKTREE `CARVE-REFUSED` WAS AN INSTRUMENT VERDICT (P31 S69, Fable-3 audit; byte-proven end-to-end) L32667 +- **§3-A.** — THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) L33098 ### optimisation level (-O0/-O2) (22) @@ -801,7 +804,7 @@ - **§362** — TWO TRAPS WHEN A CARVE MOVES A STUB INTO THE `-O0` TU (P31 S68; byte-proven, 6 fns / 2,547 ins across ov_MAIN_012 / ov_SC02_037 / ov_SC03_107) L31682 - **§388** — ★★★ — THE **-O0 COLOURING ORACLE**: simulate `stupid.c` instead of grinding spellings (P31 S69; main/func_80011380 proved a C-level WALL at 6) L32384 -### family propagation & sweeps (118) +### family propagation & sweeps (119) - **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) L502 - **§11** — Cross-binary dedup & code-sharing (Phase 11 — "one match unlocks many") L927 @@ -921,8 +924,9 @@ - **§379** — ★★★ — **MEM_IN_STRUCT_P**: THE SAME LOAD, WRITTEN AS A STRUCT MEMBER, SCHEDULES WHERE A CAST CANNOT (P31 S69; byte-proven main/func_80021284 220 ins and main/func_8002D904 217 ins, found INDEPENDENTLY by two agents) L32164 - **§396** — ★★★ — SIX LEVERS FROM THE S69 SINGLETON ROUND, INCLUDING ONE THAT ONLY A `COND_EXPR` REACHES (P31 S69) L32737 - **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) L32835 +- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) L33108 -### integration / TU plumbing (74) +### integration / TU plumbing (75) - **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) L456 - **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) L502 @@ -998,8 +1002,9 @@ - **§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) L32309 - **§378c** — ★★ — THE FIFTH DECL-BLOCKER VARIANT: THE DRAFT REDECLARES WHAT THE TU ALREADY OWNS (P31 S69) L32722 - **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) L32835 +- **§3-D.** — INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY L33140 -### build graph, splat & the harness (189) +### build graph, splat & the harness (191) - **§4** — Flag/toolchain gotchas L190 - **Build** — mechanism — per-file opt override (splat resegmentation) L307 @@ -1190,8 +1195,10 @@ - **§388** — ★★★ — THE **-O0 COLOURING ORACLE**: simulate `stupid.c` instead of grinding spellings (P31 S69; main/func_80011380 proved a C-level WALL at 6) L32384 - **§392** — ★★★ — THE SONNET-WAVE HARVEST (P31 S69): SEVEN TYPE/ORDER LEVERS THAT EACH CLOSED A MATCH L32502 - **§332b** — ★★★ — THE §332 "WALLS" ARE A PER-OBJECT ASSEMBLER MODE, NOT A C LIMIT — 6 CLOSE AS REAL C (P31 S69, Fable-3) L32702 +- **§405** — ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back L33092 +- **§3-A.** — THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) L33098 -### process, measurement & doctrine (129) +### process, measurement & doctrine (130) - **§8e** — The jtbl ALIGNMENT LAW + the pad-spec filter — multi-table .rodata spans (Phase 29, byte-proven; `.run/probe_jtbl/verdict.md`) L549 - **§3-The** — mechanism: game-code dedup is SOURCE-LEVEL, not an object swap (R-D1, the key lesson) L945 @@ -1322,8 +1329,9 @@ - **§384** — ★★★ — A CARVE-CONFIG BANK IS RED UNTIL YOU RE-EXTRACT, AND THAT LOOKS EXACTLY LIKE A FALSE BANK (P31 S69; measured twice, cost one destroyed match) L32259 - **§378b** — ★★★ — THE FOUR VARIANTS OF THE DECL BLOCKER, AND THE TWO PLACES §378 DOES **NOT** APPLY (P31 S69, all four measured the same day) L32572 - **§398** — ★★★ — `family_remap` CARRIES THE **SOURCE** TU's DECL ENVIRONMENT INTO A DESTINATION THAT ALREADY OWNS THOSE NAMES (P31 S69; measured 3 banked of 22) L32835 +- **§3-E.** — WHAT THE AGENTS REFUTED L33148 -### (unbucketed — title matched no symptom vocabulary) (319) +### (unbucketed — title matched no symptom vocabulary) (320) - **§3-How** — to use this L30 - **§1** — Idiom catalog (asm pattern → C that produces it) L39 @@ -1644,6 +1652,7 @@ - **§402** — §402 L33000 - **§403** — §403 L33024 - **§404** — §404 L33056 +- **§406** — ★★ — THE PROLOGUE-WEAVE CLASS IS MECHANICAL AND LARGE (134 open stubs) L33158 ## All sections, in order @@ -2714,6 +2723,13 @@ - **§402** — §402 L33000 - **§403** — §403 L33024 - **§404** — §404 L33056 +- **§405** — ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back L33092 +- **§3-A.** — THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) L33098 +- **§3-B.** — THE SCHEDULER DIALS (the dominant residual family this wave) L33108 +- **§3-C.** — REGISTER ALLOCATION FROM C, WITHOUT PINS L33124 +- **§3-D.** — INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY L33140 +- **§3-E.** — WHAT THE AGENTS REFUTED L33148 +- **§406** — ★★ — THE PROLOGUE-WEAVE CLASS IS MECHANICAL AND LARGE (134 open stubs) L33158 --- @@ -3792,3 +3808,10 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: ` | L33000 | §402 | §402 | | L33024 | §403 | §403 | | L33056 | §404 | §404 | +| L33092 | §405 | ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back | +| L33098 | §3-A. | THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) | +| L33108 | §3-B. | THE SCHEDULER DIALS (the dominant residual family this wave) | +| L33124 | §3-C. | REGISTER ALLOCATION FROM C, WITHOUT PINS | +| L33140 | §3-D. | INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY | +| L33148 | §3-E. | WHAT THE AGENTS REFUTED | +| L33158 | §406 | ★★ — THE PROLOGUE-WEAVE CLASS IS MECHANICAL AND LARGE (134 open stubs) | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index f78ac4c4a..fc0ec2c33 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -33088,3 +33088,91 @@ Reach for `harvest_verify` directly only as a diagnostic — for instance to A/B success line (R40). A frontier count that does not move after a reported bank is the tell; here `355 -> 314 = 41` reconciled exactly as `15+3+3+20` with main contributing zero, which is how the phantom surfaced. + +## §405 ★★★ — THE S70 WAVE HARVEST: 130 agents, 113 MATCH, and the laws they brought back + +One session, three waves (50 + 40 + 40 targets), **113 MATCH / 4 NEAR**, 132 functions banked across +four R22-green gates. The per-agent notes are preserved in each run's `journal.jsonl` under +`subagents/workflows/wf_*/`. What follows is the generalisable residue, grouped by lever family. + +### A. THE ORACLE HAS A HOLE: match_one cannot see a jump table (§405-A) +`match_one` compares **`.text` only**. gcc-2.7.2 emits switch case BODIES in source order while jump +table entry *i* points at case *i*, so **case-value and case-order are independent and `.text` pins +only the order**. A draft can therefore score a perfect closeness 0 while emitting an IDENTITY table +where the target's real table is PERMUTED — byte-witnessed on `resident/func_800D02D0` (110/110 with +`jtbl_80113F14` permuted). **A MATCH on a switch function is not evidence about its table.** Recover +the labels FROM the table (`jtbl[i]` -> block addr -> that block's delay-slot constant = `case i`), +then emit cases sorted by block address. This is R34's shape in the project's most-trusted oracle: +some historical "match_one MATCH but the gate rejected it" verdicts were the ORACLE being wrong. + +### B. THE SCHEDULER DIALS (the dominant residual family this wave) +* **Birthing-boost kill (§49/§350/§393), now with its placement rule.** sched1 boosts a + single-set pseudo's def; making it **2-set** removes the boost and sinks the insn. Every pure-C + second-set spelling (`x = x`, `x += 0`, `x &= -1`, dead-reset) is folded before `reg_n_sets` is + computed, so **the zero-byte `__asm__("" : "=r"(x) : "0"(x)) re-tie is the only reachable lever** — + and it **must sit in a LATER basic block than the boosted insn** (same-block placement fixes the + schedule but rotates the registers instead). +* **`stop_search_p` halts reorg's delay-slot scan at ANY asm.** So a laundering `__asm__` between a + copy and a branch BLOCKS `fill_simple_delay_slots`. Put the frame/launder asm LAST, or move it + into both arms, or you trade a schedule fix for a lost delay slot. +* **Comparison operand order is a LUID dial.** `limit > sum` vs `sum < limit` decides which operand + is expanded first, hence which sign-extend `loop.c` hoists first (4 -> 0, `func_8018088C`). Also + reaches conflict-driven regalloc swaps: reversing `-lim < x` to `x > -lim` moved a last-use past a + copy's birth and changed `find_reg`'s answer (`func_8017EE48`) — which REFUTES §137's "source + levers are a dead end" for CONFLICT-driven (as opposed to priority-driven) swaps. + +### C. REGISTER ALLOCATION FROM C, WITHOUT PINS +* **Variable IDENTITY picks the allocator.** A local whose live range spans two blocks goes to + global-alloc ($a0-class); a single-block one goes to local-alloc ($v1-class). Splitting or sharing + one variable is therefore a register dial (`func_8017FBCC`). +* **A value flowing into a cross-arm join is a GLOBAL allocno and loses first-fit to block-local + constants.** Duplicate the whole expression into every arm and let `cross_jump` refund the size + (`func_8017D4CC`) — a suffix-only lever, consistent with §193-C. +* **Pass-through parameters reserve argument registers for free.** Two extra params handed straight + to the callee emit ZERO instructions (self-copies deleted) but their copy-preferences hold + $a1/$a2 all function long, pushing a preference-less allocno to $a3 (`func_800CAE88`). +* **A dying HARD reg becomes local-alloc's dest suggestion** — so a pin can CAUSE the swap you are + trying to fix; keeping the value live one insn longer with a use-only asm restores it. +* **`rand() % K` in one statement vs two.** `expand_divmod` zeroes its target only when the + destination is mentioned in the dividend, so the one-statement form reuses the variable's own + pseudo as the quotient temp and stretches its live range into a hard-reg conflict (`func_8017FED8`). + +### D. INTEGRATION IS STILL THE BOTTLENECK, AND THE TU IS THE AUTHORITY +Roughly a third of these functions had a byte-correct body already and failed only on declarations. +The recurring shapes: adopt the TU's own spelling verbatim (law 2) · §37/§124 `__asm__("name")` +definition-side alias when the TU's forward decl disagrees on the RETURN axis (which +`fix_arity_callers` structurally cannot reach) · block-scope the externs and typedefs when a +file-scope one would collide with a definition later in the TU (§183) · K&R the definition when the +TU's decl is already no-proto and a parameter is not promotion-stable (§324/§99). + +### E. WHAT THE AGENTS REFUTED +* §137's source-permutation invariance is a real law for PRIORITY-driven ties and **false for + CONFLICT-driven ones** (see B above). +* §153's "cse2 puts the deleted def straight back" does **not** hold for the dead-def case: a + `do{}while(0)` stops cse1 at `NOTE_INSN_LOOP_END`, the reg goes dead, and + `delete_dead_from_cse` removes it before cse2 ever sees it. +* §257-8 and §16x disagree on volatility polarity by SITE: dropping a `volatile` use-barrier flips a + prologue save pair in one function while the volatile spelling is load-bearing in another. Diagnose + per site; do not carry the polarity across functions. + +## §406 ★★ — THE PROLOGUE-WEAVE CLASS IS MECHANICAL AND LARGE (134 open stubs) + +`sw $s0` / `move $s0,$a0` / `sw $ra` in the prologue window. **Census: 134 of 1,237 open stubs (11%)** +carry the shape. The residual is always the `sw $ra` SLOT. + +**Cause, read out of cc1's own `.i.sched2` dump** (`ov_SC02_005/func_8017F898`): bb0 is all +constant-address MEMs, so `memrefs_conflict_p` (sched.c:614 — "frame-pointer addresses cannot +conflict with static variables") finds NO dependence; `sw $ra` is ready at T-2 and +`schedule_select`'s `potential_hazard` (memory unit beats ALU, sched.c:2616) picks it early, sinking +it to just above the `bne`. + +**Twelve variants were measured INERT** — volatile locals, arrays, structs, `/s`-defeating casts, +address-taken scalars, statement order, cached-global and volatile-global. + +**The lever:** a NON-volatile `__asm__("" : : : "memory")` immediately after the parameter copy. The +BLK clobber gives `sw $ra` a successor, so it is only ready after the load is picked and lands back +at index 3. + +**Why this is a SWEEP and not an idiom (the project thesis):** one known lever against 134 known +targets is exactly the "is this MECHANICAL?" test the harvest gate asks. Build the sweep — apply the +lever to the class, gate the batch — before drafting any of these individually.