- c12: c3's reading held on both twins — the angle as the handler's first argument + tmp reused as the later operand;
the stale 'jalr with no args' comment corrected in the 135 files whose body now passes it
- c10: jump2 cross-jump merged two walk tails (exits now fall to the single final return), the s16 SUBREG gate, and
func_80135480 called at its real arity; its answer was func_80135888 in another file
- delever_pack related.txt: lever-free bodies in the overlay sharing a func_/D_ symbol, ranked (known-true: top hit for
func_80135A4C is func_80135888); METHOD_S103 +6 emitter entries; SETUP rows
- apply-body IDENTICAL x3, propagate 131/131 x2 + 133/133; check-all 218 passed 0 failed; lever_census 19,276 marked 0 UNMARKED
- closes, each --try 0 then apply-body IDENTICAL + propagate N/N 0 refused: func_80133AB0 (u16 width moves), func_80130D48
(one call per goto-tail site), func_80135168 (reused temps split + H16 member store), func_80134A74 (widths + join
statement in both arms), func_80148AFC (implicit handler argument + later operand), func_8015D738 (jump threading:
re-read + a do-while on precedent, the class raised with Drew), func_80135004 (temp split + argument from its global)
- func_8017EEC0: the uninitialised a0v T4 tus10 left is the parameter (8/8, IDENTICAL)
- CI red since cb2fb5e6d: verbatim_check --strict saw the DECOMPILE-NOW row func_8017EEC0 converted; row removed (one
row), --update keeps order + UTF-8 (proven equal to the hand fix), verbatim_check --strict now in make tools-health
- delever.split_reused_locals = family R23 (selftest + two refusals; known-true: joint split = the agents' measured 12/26)
- check-all 218 passed 0 failed (twice); lever_census 20,206 marked 0 UNMARKED; Drew: at most five concurrent agents
- agent c2 (Opus): a second pointer q = p + 5 stepped in lockstep with p kept a second biv alive (loop.c strength
reduction, -dL 'Cannot eliminate biv'); one pointer lets combine_givs fold every field read onto one base
- bank: apply-body IDENTICAL, propagate 130/130, check-all 218 passed 0 failed, lever_census 23,988 marked 0 UNMARKED
- delever.merge_walked_pointers = family R22 (selftest + two refusal controls; known-true: the agent's start text's
candidate is its closing body, --try score 0); leads the COUNT class after R19 in delever_search; SETUP row
- S103 opening: the method addendum .run/P36/agents/METHOD_S103.md; wave c launched (six agents); Fable out of credits,
c5/c6 relaunched on Opus
Not banked, and the agent said so itself: it solved the whole tail — instructions 32 to 489 of 490 byte-identical in
plain C with the $4 pin gone — by hoisting one statement above two derived pointers, a COLOURING move rather than a
scheduling one (the scheduler's RTL order is identical in both candidates, so the tree's header note blaming it
describes the assembly, not the RTL). The head is a proven wall: find_best_addr (cse.c:2663-2665) folds the base to an
absolute address because its only set is a symbol_ref, and its known-true control keeps its base in plain C only because
both uses are at offset 0. It then labelled its two remaining improvements COMPENSATING ERRORS — a width change that
deletes the target's real andi to cancel an extra instruction — and wrote 'nothing here is bankable' instead of handing
back a 16 dressed as progress.
Two pack defects fixed from its report:
- neighbours.txt carried the @class/@stuck LINES but not the header comment they sit in, and that comment is an
eight-point English explanation of every lever in the body, including the tail crack stated outright. The pack now
ships the target's own header in full. A grep for tags is not a substitute for the paragraph it sits in.
- history.txt's line numbers are relative to the evolving text, so reconstructing a path by hand lands elsewhere (b9
reached 51 where the engine reproduces 16 in one round). The pack now ships the best candidate's text as best_body.c.
check-all: 218 passed, 0 failed of 218
lever_census --check: 24,119 pin/asm sites, 24,119 marked !FAKE, 0 UNMARKED — OK
Three moves, each predicted from a dump before it was compiled:
- while -> a guarded do-while (29 to 22). Cross-jump (jump.c:1969 -> find_cross_jump :2371, from toplev.c:3142) had
matched the load in front of the jump against the one in front of the bottom test and deleted three instructions; the
guarded form makes the two tails differ.
- the duplicated pre-loop call block -> goto (22 to 6). This is an allocno_compare rank move (global.c:585-611): the
priority is floor_log2(refs)*refs/live, reg_n_refs is loop-weighted (flow.c:2067), the in-loop copy of that call is
worth two references, and deleting the out-of-loop copy takes exactly one off — 8 to 7 crosses a floor_log2 step and
drops the pointer's priority from 3157.9 to 1891.9. The predicted allocation order matched the dump exactly. The
rewrite is byte-neutral on its own: reorg steals the target's first insn into the delay slot and retargets.
- the two-arm mask temp inlined (6 to 0): set in two arms it has two deaths, fails local-alloc.c:472, and combine_regs
bails at :1774, so it went to global allocation and took its copy preference.
Harvested as R21 second_consumer, from agents b2 and b6 together: give a computed value a second consumer before its
copy, either by chaining (v = slot = E) or by hoisting the store above it. cse deletes such a copy only when the
producer sits immediately before it (cse.c:7440-7501, guard :7454-7460), and flow links only the FIRST following use
(flow.c:2076-2091), so a store in between defeats both. R9 can never produce it — the two statements share the
identifier, so its independence guard refuses the swap. Known-true: the joint form scores 0 on b6's pre-bank text, and
the single-site forms do not, which is the third measured case this session of a joint edit no hill-climb can reach.
Also recorded from b8, worth a pre-check later: declaration-order moves are PROVABLY DEAD on a register residual whose
allocnos have distinct priorities, because global.c:604-610 compares priority first and only ties by allocno number —
4,811 compiles of those candidates sat flat because of it.
- the move: narrow every local in the counter's def-use chain together — the counter, its +/-1 temp and the copy-back —
and do it for BOTH chains at once. Four instructions were MISSING, not miscoloured, three of them the moves the $0 pin
was faking. insert_regs (cse.c:1029-1032, early bail :1018-1020) puts two pseudos in one equivalence class only when
their MODES match, so an all-int copy-back is collapsed and swept, while the narrowed one is a truncation: no
equivalence, the wide temp stays live and reaches reload as the move the target has. The fourth instruction is
strength_reduce minting a shift giv from a wide counter whose every use is a cast; a HImode pseudo cannot be that giv.
delever --propagate: 127 of 127 sibling(s) banked, 0 refused. 26,202 -> the census below.
- R20 narrow_chains: the agent PROVED the joint form is necessary, and the generator reproduces it. Single declarations
scored 45/72/51/24, each chain alone 43, both chains together 0 — every intermediate worse than the search's own best
of 11, so a beam over R12's one-declaration width moves cannot reach the answer from either side. Seven runs and 4,811
compiles stalled at 11; R20 offers six candidates and the right one is a single compile.
- known-true check: run on b3's pre-bank text, R20's joint signed candidate scores 0 (MATCH) and its single-chain
candidates score 43 and 51 — the agent's own hand-measured numbers, reproduced by the tool.
- chains are built conservatively from the body's text (two locals linked when one is assigned from the other, through a
cast or a +/- constant), and only whole components are offered, so the partial narrowings the measurement showed are
always worse are never generated. Selftest: the chain is found whole, an unlinked local is not pulled in, and a body
with no linked pair offers nothing.
- the move: delete the hand-walked pointer's self-increment and recompute p = &tbl[i] from the loop counter each
iteration. The lever-free body had TWO induction variables — the loop dump says 'Cannot eliminate biv 73: biv used in
insn 50' (loop.c:5976) because the pointer is itself a call argument — and combine_givs (loop.c:5494/:5527) then
merged the three +12 field addresses into one giv whose benefit clears the not-worth-while gate at loop.c:3822-3828,
reducing it to a THIRD walking register and forcing a fourth callee-saved one: the +4 instructions and the whole
recolouring. Indexing instead leaves one biv, the +12 rides as an immediate, and the body is byte-identical.
delever --propagate: 126 of 126 sibling(s) banked, 0 refused. 26,456 -> 26,202 sites.
- THE HEADLINE IS THE METHOD, not the crack: the answer was written in English thirty lines above, in the // @class:
header of an already-matched sibling in the same file, which spells out 'recompute p = &D[i] each iteration (NOT p++)
so gcc reduces base+i*0x10 into a SINGLE pointer IV'. The pack sent agents to the cookbook and to the compiler source
and never to the target's own neighbours. This project has been leaving itself notes for months and nobody was reading
them.
- delever_pack.py now writes PACK/neighbours.txt — the comment headers of the three matched functions either side of the
target, plus every @class/@stuck/@crack note in the translation unit — and the brief makes reading it step 0.
tool_census's two enumerations disagreed on one file: the new tool was written but never added, so the dictionary row
existed for a path git did not carry. That is exactly the disagreement the second oracle is there to find.
Six T7 agents independently reached score 0 by restoring an argument the decompiled source had dropped, and no generator
could reach the class because every other family rewrites statements that exist while this changes a call's ARITY. R19
closes that gap without cracking anything: it finds every call whose in-scope declaration is narrower than the callee's
real definition, then offers one candidate per value already in scope (each parameter, each local declared before the
call) and lets the byte oracle pick. The missing argument is never inferred.
- known-true check: run on the pre-bank text of func_8017A3D8, which agent a12 solved by hand, R19 emits that agent's
exact fix and --try scores it 0 (OTHER; mine 53 ins, target 53) — MATCH.
- two spellings were wrong before that passed. It took the return type from the DEFINITION and produced
((void (*)(s32))f)(a) != 0, which cannot compile because the defining TU says void where this one says int — it now
repairs the arity only and keeps the TU's declared return type. And it required a simple statement, so it found
nothing on the very body it was written from: these calls live in and far more often
than in a plain statement.
- it also sees the cast-wrapped form ((s32 (*)(void))f)(), which is how m2c usually spells a dropped argument, and
replaces the whole wrapper rather than nesting a second cast.
- ranked FIRST in every residual class: it emits candidates only for calls whose declaration provably disagrees with the
definition, so it costs nothing when it does not apply. The engine selftest's ordering invariant is updated to say so
rather than being widened again.
- argcheck now carries each definition's return type, which the cast route needs.
- selftest: two positive assertions and two controls (the declared return type is kept; the definition's is refused; a
call inside a return statement is seen; a matching declaration offers nothing).
tools/alloc_table.py had only ever printed pseudos that landed in $s0-$s7/$fp, and it depended on 'Register N in M.'
lines the dumps often do not emit — so two agents in the burst were handed an EMPTY or one-row table and read it as an
answer. That is the silently-narrowed-scope defect class: a true number about a scope far narrower than the reader
believes.
- it now prints every pseudo with refs, live length, block, conflicts, copy preferences and allocno_compare's priority,
takes the hard register from either dump, and ASSERTS ITS COVERAGE against the .greg order line (R32) — a named gap and
a non-zero exit instead of a confident subset. A missing dump section is refused loudly rather than printed as an
empty table.
- documented honestly: .greg carries the INPUTS to global allocation (order, conflicts, preferences), not the final
assignment, so a global allocno's hard register prints as '-'. That is the dump's shape, not a gap.
- verified on a real dump from an agent's pack: 4 pseudos, the order line, preferences and conflicts all parsed,
coverage OK. The old tool would have printed nothing for it — none of the four is callee-saved.
- tools/cc1_dumps_tu.sh: add -I<the TU's own directory> (an agent found it silently preprocessing to 44 lines and
exiting 0 on any TU with relative includes), add -dR for the post-reload schedule, and REFUSE a preprocess under 200
lines instead of producing empty dumps.
- the agent brief now says to read the allocation table first for any register residual, that the .greg assignment is
absent by design, and that the residual text cannot distinguish a missing instruction from wrong registers — one agent
chased a register lever for hours when the defect was a cse store-to-load forward that had deleted a load.
- a22: func_8017B238 closed by giving the if-arm's pointer and the else arm's first table address one function-scope
local. Three decisions turn on that edit, all dump-proven: make_regs_eqv's head rule (cse.c:840-857), set_preference
stripping one RTX level so an arithmetic set inherits its operand's register (global.c:1535), and combine_regs with
birthing_insn_p's reg_n_sets == 1 (local-alloc.c:1765-1788, sched.c:2469) — which is why the merge must be with the
else arm's non-call-crossing temp. 26,714 -> 26,462 sites.
- a14 reaches score 0 on func_80139BE0 but only by an INVENTED identically-zero term whose sole purpose is to keep a
value live. NOT BANKED: an invented no-op expression is a compiler-forcing construct in C clothing, and worse than the
marked launder it replaces because the launder is counted and this would be silent. The phase's own rule is ban the
silence, not the lever. Parked for the structs/types phase with its reading; the tree comment above it ('no pure-C
spelling survives that fold') is refuted.
- a6 corrects cookbook 455: cse1 (cse.c:7439-7502) rewrites the producer's destination to the copy's whenever the
producer is the immediately preceding insn; combine only finishes the job once that adjacency is broken. It enumerated
the three lever-free blockers can_combine_p admits and showed the body can pay for none, then scanned all 4,284 built
objects for the shape — 101 hits, every lever-free precedent paying with a genuine second use, a narrow local with two
consumers, or a join label.
- a24's residual was one absent load: cse forwards a just-stored halfword so no lh is emitted, and seven branch
displacement mismatches were downstream of it. Its method gap is the instrument to fix next — three agents have now
asked for local-alloc's quantity table in the pack, and alloc_table.py prints an empty or one-row table because it
keys on dump lines that are often absent.
- Drew's struct question answered on the record: structs are not in the binary (types are erased; no metadata in a
retail build), what is there is base + offset + width + stride, so a struct is an inference across every function
touching a base — which makes per-function struct invention the wrong unit and is the failure P35 already recorded.
Recommendation: keep pins as the main lane, build a zero-token struct evidence census beside it, park stuck pins with
their evidence, and fix call signatures first because they are the bigger and cheaper blocker (471 narrow call sites
in 323 pinned bodies). Measured: 372,224 raw cast dereferences against 92,624 struct member accesses.
search: 0 of 139 exemplars matched lever-free in 0.54 h (0 of 7,077 bodies behind them; 52,566 compiles) — NO-MATCH 136 · BANK-REFUSED 3
- the three refusals are the three fleet copies of func_80136824, each a real score 0 (R15 sink + R12 width + R14
param-width) blocked by a contract rather than by a bad body: the engine verifies the whole candidate text but hands
apply_body_core only the definition, and --propagate remaps that body to siblings, so a generator that edits lines
outside the definition can never bank. R14 is the only such generator.
- my first diagnosis was wrong and was discarded rather than shipped: I guessed the conflicting declaration was in a
shared header and built a 2,431-name index to refuse on, and the index said the function is not in it. Reading cmd_run
gave the real answer.
- two fixes: param_widths refuses outright when the TU declares the function anywhere but at its definition
(protos_outside_definition; the earlier R14 banks had no such prototype, so nothing that worked is lost), and the engine
names the condition itself with a new OUT-OF-BODY verdict instead of letting the bank die on a compiler error that reads
like a bad body. Controls both ways in the selftest.
- the steering measurement (R41): across s1-s4 the head's 57 classes have absorbed ~128,000 compiles for 6 closes, all of
them R15's and all in the first sweep. The head is resistant to every mechanical generator at this width; sweeps pay on
the tail and on targeted families, and the head is what agents are for.
- open by name for the types phase: func_80136824 (133 copies) has a real crack that needs its prototype widened with its
definition — the second measured case where a declaration, not codegen, stands between us and the bytes.
The third agent produced no bank and a precise refutation plus a generator, which is the deliverable the brief asks for.
- it refuted the a2 hypothesis on its own body: git grep returns 1,770 declarations in two forms, both (s32 a0), no (void)
anywhere, and the pin is on a local rather than the parameter. Three lever-free spellings reach the target's complete
register assignment, so the class is reachable from plain C.
- its best is score 2, class ORDER, 89/89 instructions, every register correct, one displaced bystander store. The target's
sw sits inside the lbu->addiu window and that position is forced: anti_dependence and true_dependence (sched.c:817/845)
both hold, so the store can neither hoist nor sink. Post-sched1 stream and reg_live_length then match ours, leaving
reg_n_refs — computed by flow on the pre-combine RTL — as the only remaining input.
- R18 moves one simple statement to each other position in its own block, up to six away. R9's adjacent swap is the special
case; the distance is the point. It costs no instruction where R7's LOOP notes are a full sched1 barrier and always cost
one displaced insn, so R18 is ranked ahead of R7 in every class.
- two wrong spellings before the known-true check passed: identifier-disjointness as a requirement offered three candidates
and none of them the agent's (it is only an ordering preference now — byte-identical output is the same program, so the
oracle is the whole correctness proof, which is R9's own footing), and a blank line counted as an obstacle, so the
generator never offered the very move it was written from. It now reproduces that body exactly: bystander @21->17.
- delever_pack.py now writes each trace candidate's residual class beside its score, from the agent's method note: a bare
number hid that a move had already turned this body's residual from REG into ORDER.
- delever --selftest OK (3 new controls incl. the nested-block refusal); delever_search --selftest OK; tool_census OK.
- R16 writes a local whose only assignment is one integer literal at every use and deletes it. R6 stops at a temp read
exactly once, so a holder read four times was invisible to the search and its whole family with it. Deleting it is
byte-neutral alone but removes a quantity from the block, which is what lets the next move reach the allocator.
- R17 splits a run of consecutive same-literal assignments by moving the nearest differently-valued one into it, at each
interior split point. find_free_reg's live-range scan (local-alloc.c:2109-2110): while the two constants' ranges are
disjoint they share a caller-saved register; splitting makes the first live across the second and it takes another colour.
- known-true check: on the seed that keeps func_80168828's semantically-forced $4 pin, R16 then R17 reaches
score 0 (OTHER; mine 108 ins, target 108) — MATCH at three of the six offered split points, in ten compiles where the
blind search needed 2,271.
- the engine selftest's caller-saved assertion is now the ordering invariant (every targeted lever before every blind
family) rather than a fixed window widened once per new generator.
- delever --selftest OK (4 new controls); delever_search --selftest OK; tool_census --check OK; SETUP row (R21).
The harvest half of the one-at-a-time loop (R16): agent a1's reading of func_80156044 is now a move the engine can make
on any body, so the remaining head classes get it for free.
- R15 sinks the statement AFTER an if/else chain into every arm and deletes the variables it consumed:
`if (c) { v = e1; } else { v = e2; } w = f(v);` -> `if (c) { w = f(e1); } else { w = f(e2); }`.
- it is a REGISTER move, not a scheduling one. A value set in every arm and read after the merge is a cross-block pseudo
local-alloc never gives a quantity (local-alloc.c:472, next_qty reset at :517), so the arm holds two quantities and
takes block_alloc's unrolled case 2 (:1499-1502, qty_compare :1578-1596). Sinking makes it a third block-local
quantity, and case 3 (:1491-1496) falls through into case 2 and applies that comparison a second time, undoing its own
exchange — the two caller-saved colours swap. It also takes the value out of global.c, where set_preference
(global.c:1535+) had given it a copy preference through the merge result's argument copy.
- applicability is checked, never assumed: each consumed variable must be assigned exactly once in every arm by a simple
statement, appear in the merge statement, and occur nowhere else in the function.
- if_chains() counts a line's CLOSING braces before its opening ones. On a `} else if (...) {` line the two net to zero
and the first version's depth counter never closed the arm — the generator found 0 candidates on the very body it was
written from. Caught by running it on that known-true case before believing it.
- ranked third in REG-caller / REG-mixed / COUNT; the engine selftest's "R5 in the first three" assertion widened to
"R5 and R15 in the first four" rather than de-ranking the new move.
- verified: delever --selftest OK (3 new controls: a variable read after the merge, a variable one arm does not set, the
brace walk's three arms); delever_search --selftest OK; and the known-true check — R15 run on func_80156044's
pre-bank text emits the agent's crack and `--try` scores it
`score 0 (OTHER; mine 74 ins, target 74) — MATCH`.
- SETUP row rewritten (R21), kit corpus regenerated, tool_census --check OK (371 copies + 30 pointers, 0 gaps).
- no src/ change in this commit; the sweep of the other 56 head classes follows.