phase11: cookbook 116-118 — the ranker's blind spot, a new failure signature, and two negatives
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.
This commit is contained in:
@@ -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.**
|
||||
|
||||
Reference in New Issue
Block a user