From 71aa4a2bc286e2ee3f92cd3b721becbbac40ad64 Mon Sep 17 00:00:00 2001 From: Christopher Williams Date: Thu, 24 Sep 2026 10:20:47 -0400 Subject: [PATCH] =?UTF-8?q?phase11:=20cookbook=20116-118=20=E2=80=94=20the?= =?UTF-8?q?=20ranker's=20blind=20spot,=20a=20new=20failure=20signature,=20?= =?UTF-8?q?and=20two=20negatives?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 116: worker A's hypothesis that the ranker cannot see LIVE RANGES (its conversion rate went to zero over three consecutive rows, all failing on register allocation with the structure fully confirmed). I tried to make it computable -- callee-saved registers saved and s-registers per call -- and the proxy FAILED: matches span 0.00-2.00 s/call and failures span 0.17-1.33, with a matched row having the HIGHEST s-register count and another matched row having 16 calls and 0 saved registers. The hypothesis is not refuted; the proxy is just not a good operationalisation of 'live range'. Recorded as an open axis. 117: worker C's new signature -- correct control flow, +3 instructions, all three being j/jr delay slots. DISTINCT from a nesting error (both give a small residual, but nesting moves branch displacements while this moves instructions ACROSS a jump). Belongs with the post-pass family. 118: call COUNT does not separate a real block from a call chain -- worker C's matched 0x80058CE8 is four loops that each call, and its false positive has zero calls. Fails in both directions; recorded so nobody re-derives it. --- docs/MATCHING_COOKBOOK.md | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/docs/MATCHING_COOKBOOK.md b/docs/MATCHING_COOKBOOK.md index 60e1410..298a18a 100644 --- a/docs/MATCHING_COOKBOOK.md +++ b/docs/MATCHING_COOKBOOK.md @@ -1840,3 +1840,81 @@ mask writes to the same field are two source statements, not one — the same pr Companion: the status **load is hoisted above nine halfword clears** by the scheduler, so the clears' source order is only observable through the **store order**. + +### 116. A SECOND FAILURE AXIS exists — but the cheap proxy for it FAILS (worker A + coordinator) + +**Worker A's hypothesis, which is the most valuable thing said about the ranker's limits:** its +conversion rate went to **zero over three consecutive rows**, and all three failed for the same +reason — **register allocation, not source shape**. Its framing: + +> Every row I have **matched** has a **data-movement** shape — copies, table walks, repetitive call +> sequences. Every row I have **failed** has a **live-range** shape: a flag whose value is known at +> the return, two parameters that are interchangeable, a pointer reloaded per use. +> **The ranker measures the instruction stream, not the live ranges, so it cannot see this.** + +Worker A's proposed discriminator: *does the body keep any value live across a call that is not a +pointer or an array? If yes, expect an allocator residual; if no, the redundancy score is +trustworthy.* + +**I TRIED TO MAKE THAT COMPUTABLE AND THE PROXY FAILED.** Proxy: the number of callee-saved +registers the body saves (values the allocator decided must survive a call), and s-registers per +call. + +| row | outcome | redundancy | s-regs saved | calls | s/call | +|---|---|---|---|---|---| +| `0x8009C904` | MATCH | 0.81 | 2 | 3 | 0.67 | +| `0x80036DA4` | MATCH | 0.77 | **6** | 3 | **2.00** | +| `0x800556E8` | MATCH | 0.67 | 1 | 1 | 1.00 | +| `0x80068910` | MATCH | 0.82 | 0 | 0 | 0.00 | +| `0x800914E4` | MATCH | 0.81 | 3 | 10 | 0.30 | +| `0x8006B7C0` | MATCH | 0.80 | 0 | 16 | 0.00 | +| `0x8009F264` | **FAIL** | 0.67 | 4 | 3 | 1.33 | +| `0x8007F774` | **FAIL** | 0.70 | 1 | 1 | 1.00 | +| `0x80017C6C` | **FAIL** | 0.33 | 2 | 2 | 1.00 | +| `0x800B7264` | **FAIL** | 0.77 | 5 | 10 | 0.50 | +| `0x80058DEC` | **FAIL** | 0.69 | 5 | 4 | 1.25 | +| `0x800FE878` | **FAIL** | 0.39 | 1 | 6 | 0.17 | + +**The ranges overlap completely** — matches span 0.00–2.00 s/call, failures span 0.17–1.33. **The +proxy does not separate them.** Note in particular that a *matched* row has the **highest** +s-register count (6) and another matched row has **16 calls and 0 saved registers**. + +**So the hypothesis is not refuted — the proxy is simply not a good operationalisation of "live +range".** Worker A's description is about *which values* stay live and *whether the allocator has a +choice*, not about how many registers are spilled. Recording it as an open axis: **the ranker has a +known blind spot and no cheap proxy for it yet.** Anyone who finds one should say so. + +### 117. "Correct control flow, +3 instructions, all three `j`/`jr` delay slots" is its OWN signature (worker C) + +Worker C's `0x80103544` (696 B, 6 attempts): candidate **708 vs 696 (+12)**, and **the control flow +is structurally identical** — all 15 branches, same relative targets, same arm order, one back edge, +four exits. The entire residual is **three delay slots the original's reorg filled and the candidate +left as nops:** + + A2 arm: j end with sw a2,28(s2) IN the slot + A3 arm: j end with sw a1,28(s2) IN the slot + epilogue: jr ra with addiu sp,sp,32 IN the slot (candidate: addiu; jr ra; nop) + +All three are the same shape: *the instruction immediately preceding the jump moved after it.* + +**This is a DISTINCT signature from a nesting error (finding 95)** — both produce a small residual at +correct-ish length, but nesting errors move *branch displacements* while this moves *instructions +across a jump*. Worker C notes its own matched `0x80031FC4` **does** have a filled delay +(`j join1; sw v0,32(sp)`), so cc1 fills when the source is right; the trigger here is not any of the +five shapes it tried (nesting order, arm order, `tbl`-first declaration, `goto`-instead-of-`break`, +splitting `V8`). **So it is a source-shape hunt, not a brace hunt** — and it belongs with the +post-pass family, since the fill is what the original's assembler did. + +### 118. Call COUNT does not separate a real block from a call chain — measured, both directions (worker C) + +Worker C tried "a long run with few calls is a real block, a long run with many calls is a call +chain" as a discriminator and **it fails in both directions:** + +- Worker C's **matched** `0x80058CE8` is **four loops that each call** `0x80012D8C` — many calls, + and a genuine repeated block. +- Its **false positive** (`0x8001C8AC`) has **zero calls**. + +**So call count does not separate them either.** Recorded as a negative so nobody re-derives it. The +one weak signal in worker C's table: its false positive sits at a structurally-repeated run of +**10** and the run is exactly the `multu`/`mflo`/`sra` chain, while rows above run **18** are +plausibly real blocks — **but that is a guess from one false positive, not a measurement.**