From d30ccc9a723fbe123d5fcab873106ec618f8f50b Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Thu, 10 Sep 2026 13:31:47 -0600 Subject: [PATCH] =?UTF-8?q?phase-36:=20T7=20agent=20b8=20=E2=80=94=20func?= =?UTF-8?q?=5F80135888,=20the=20largest=20class=20left,=20closed=20with=20?= =?UTF-8?q?all=20five=20levers=20gone=20(134=20bodies;=2024,789=20?= =?UTF-8?q?=E2=86=92=2024,119=20sites,=20R22=20218/218)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../agents/ov_SC04_011__func_80133784/body.c | 14 +- .../agents/ov_SC04_011__func_80135888/body.c | 17 +- .../ov_SC04_011__func_80135888/mechanism.md | 118 ++++++ .../agents/ov_SC04_011__func_8013F350/body.c | 238 ++++++++++++ .run/P36/census/lever_census.json | 80 ++-- .run/P36/census/lever_census.txt | 22 +- .run/P36/delever/calibration.json | 346 +++++++++--------- .run/P36/delever/ledger.jsonl | 134 +++++++ decomp-architect/corpus/tools/P10/delever.py | 98 ++++- .../corpus/tools/P10/delever_pack.py | 1 + .../corpus/tools/P10/delever_search.py | 16 +- docs/lever-progress.tsv | 1 + docs/levers.md | 5 +- src/ov_MAIN_012/ov_MAIN_012_jr_80131340.c | 24 +- src/ov_SC01_000/ov_SC01_000_jr_80135888.c | 24 +- src/ov_SC01_001/ov_SC01_001_jr_80135888.c | 24 +- src/ov_SC01_004/ov_SC01_004_jr_80135888.c | 24 +- src/ov_SC01_005/ov_SC01_005_jr_80135888.c | 24 +- src/ov_SC01_008/ov_SC01_008_jr_80135888.c | 24 +- src/ov_SC01_009/ov_SC01_009_jr_80135888.c | 24 +- src/ov_SC01_074/ov_SC01_074_jr_80135888.c | 24 +- src/ov_SC01_077/ov_SC01_077_jr_80135888.c | 24 +- src/ov_SC01_080/ov_SC01_080_jr_80135888.c | 24 +- src/ov_SC01_084/ov_SC01_084_jr_80135888.c | 24 +- src/ov_SC02_000/ov_SC02_000_jr_80135888.c | 24 +- src/ov_SC02_004/ov_SC02_004_jr_80135888.c | 24 +- src/ov_SC02_005/ov_SC02_005_jr_80135888.c | 24 +- src/ov_SC02_011/ov_SC02_011_jr_80135888.c | 24 +- src/ov_SC02_015/ov_SC02_015_jr_80135888.c | 24 +- src/ov_SC02_016/ov_SC02_016_jr_80135888.c | 24 +- src/ov_SC02_017/ov_SC02_017_jr_80135888.c | 24 +- src/ov_SC02_021/ov_SC02_021_jr_80135888.c | 24 +- src/ov_SC02_026/ov_SC02_026_jr_80135888.c | 24 +- src/ov_SC02_027/ov_SC02_027_jr_80135888.c | 24 +- src/ov_SC02_028/ov_SC02_028_jr_80135888.c | 24 +- src/ov_SC02_031/ov_SC02_031_jr_80135888.c | 24 +- src/ov_SC02_035/ov_SC02_035_jr_80135888.c | 24 +- src/ov_SC02_037/ov_SC02_037_jr_80131340.c | 24 +- src/ov_SC02_039/ov_SC02_039_jr_80135888.c | 24 +- src/ov_SC02_041/ov_SC02_041_jr_80135888.c | 24 +- src/ov_SC03_001/ov_SC03_001_jr_80135888.c | 24 +- src/ov_SC03_002/ov_SC03_002_jr_80135888.c | 24 +- src/ov_SC03_003/ov_SC03_003_jr_80135888.c | 24 +- src/ov_SC03_006/ov_SC03_006_jr_80135888.c | 24 +- src/ov_SC03_007/ov_SC03_007_jr_80135888.c | 24 +- src/ov_SC03_010/ov_SC03_010_jr_80135888.c | 24 +- src/ov_SC03_011/ov_SC03_011_jr_80135888.c | 24 +- src/ov_SC03_012/ov_SC03_012_jr_80135888.c | 24 +- src/ov_SC03_013/ov_SC03_013_jr_80135888.c | 24 +- src/ov_SC03_014/ov_SC03_014_jr_80135888.c | 24 +- src/ov_SC03_023/ov_SC03_023_jr_80135888.c | 24 +- src/ov_SC03_024/ov_SC03_024_jr_80135888.c | 24 +- src/ov_SC03_028/ov_SC03_028_jr_80135888.c | 24 +- src/ov_SC03_029/ov_SC03_029_jr_80135888.c | 24 +- src/ov_SC03_030/ov_SC03_030_jr_80135888.c | 24 +- src/ov_SC03_031/ov_SC03_031_jr_80135888.c | 24 +- src/ov_SC03_089/ov_SC03_089_jr_80135888.c | 24 +- src/ov_SC03_090/ov_SC03_090_jr_80135888.c | 24 +- src/ov_SC03_091/ov_SC03_091_jr_80135888.c | 24 +- src/ov_SC03_092/ov_SC03_092_jr_80135888.c | 24 +- src/ov_SC03_093/ov_SC03_093_jr_80135888.c | 24 +- src/ov_SC03_094/ov_SC03_094_jr_80135888.c | 24 +- src/ov_SC03_095/ov_SC03_095_jr_80135888.c | 24 +- src/ov_SC03_096/ov_SC03_096_jr_80135888.c | 24 +- src/ov_SC03_097/ov_SC03_097_jr_80135888.c | 24 +- src/ov_SC03_098/ov_SC03_098_jr_80135888.c | 24 +- src/ov_SC03_099/ov_SC03_099_jr_80135888.c | 24 +- src/ov_SC03_100/ov_SC03_100_jr_80135888.c | 24 +- src/ov_SC03_101/ov_SC03_101_jr_80135888.c | 24 +- src/ov_SC03_102/ov_SC03_102_jr_80135888.c | 24 +- src/ov_SC03_103/ov_SC03_103_jr_80135888.c | 24 +- src/ov_SC03_104/ov_SC03_104_jr_80135888.c | 24 +- src/ov_SC03_105/ov_SC03_105_jr_80135888.c | 24 +- src/ov_SC03_107/ov_SC03_107_jr_80131340.c | 24 +- src/ov_SC03_108/ov_SC03_108_jr_80135888.c | 24 +- src/ov_SC03_109/ov_SC03_109_jr_80135888.c | 24 +- src/ov_SC03_110/ov_SC03_110_jr_80135888.c | 24 +- src/ov_SC03_111/ov_SC03_111_jr_80135888.c | 24 +- src/ov_SC03_112/ov_SC03_112_jr_80135888.c | 24 +- src/ov_SC03_113/ov_SC03_113_jr_80135888.c | 24 +- src/ov_SC03_114/ov_SC03_114_jr_80135888.c | 24 +- src/ov_SC03_115/ov_SC03_115_jr_80135888.c | 24 +- src/ov_SC03_116/ov_SC03_116_jr_80135888.c | 24 +- src/ov_SC03_117/ov_SC03_117_jr_80135888.c | 24 +- src/ov_SC03_118/ov_SC03_118_jr_80135888.c | 24 +- src/ov_SC03_121/ov_SC03_121_jr_80135888.c | 24 +- src/ov_SC03_124/ov_SC03_124_jr_80135888.c | 24 +- src/ov_SC03_125/ov_SC03_125_jr_80135888.c | 24 +- src/ov_SC04_000/ov_SC04_000_jr_80135888.c | 24 +- src/ov_SC04_002/ov_SC04_002_jr_80135888.c | 24 +- src/ov_SC04_003/ov_SC04_003_jr_80135888.c | 24 +- src/ov_SC04_004/ov_SC04_004_jr_80135888.c | 24 +- src/ov_SC04_005/ov_SC04_005_jr_80135888.c | 24 +- src/ov_SC04_006/ov_SC04_006_jr_80135888.c | 24 +- src/ov_SC04_007/ov_SC04_007_jr_80135888.c | 24 +- src/ov_SC04_008/ov_SC04_008_jr_80135888.c | 24 +- src/ov_SC04_009/ov_SC04_009_jr_80135888.c | 24 +- src/ov_SC04_010/ov_SC04_010_jr_80135888.c | 24 +- src/ov_SC04_011/ov_SC04_011_jr_80135888.c | 24 +- src/ov_SC04_012/ov_SC04_012_jr_80135888.c | 24 +- src/ov_SC04_015/ov_SC04_015_jr_80135888.c | 24 +- src/ov_SC04_016/ov_SC04_016_jr_80135888.c | 24 +- src/ov_SC04_018/ov_SC04_018_jr_80135888.c | 24 +- src/ov_SC04_020/ov_SC04_020_jr_80135888.c | 24 +- src/ov_SC05_000/ov_SC05_000_jr_80135888.c | 24 +- src/ov_SC05_001/ov_SC05_001_jr_80135888.c | 24 +- src/ov_SC05_002/ov_SC05_002_jr_80135888.c | 24 +- src/ov_SC05_003/ov_SC05_003_jr_80135888.c | 24 +- src/ov_SC05_004/ov_SC05_004_jr_80135888.c | 24 +- src/ov_SC05_005/ov_SC05_005_jr_80135888.c | 24 +- src/ov_SC05_006/ov_SC05_006_jr_80135888.c | 24 +- src/ov_SC05_007/ov_SC05_007_jr_80135888.c | 24 +- src/ov_SC05_008/ov_SC05_008_jr_80135888.c | 24 +- src/ov_SC05_009/ov_SC05_009_jr_80135888.c | 24 +- src/ov_SC05_010/ov_SC05_010_jr_80135888.c | 24 +- src/ov_SC05_011/ov_SC05_011_jr_80135888.c | 24 +- src/ov_SC05_017/ov_SC05_017_jr_80135888.c | 24 +- src/ov_SC05_018/ov_SC05_018_jr_80135888.c | 24 +- src/ov_SC06_000/ov_SC06_000_jr_80135888.c | 24 +- src/ov_SC06_006/ov_SC06_006_jr_80135888.c | 24 +- src/ov_SC06_008/ov_SC06_008_jr_80135888.c | 24 +- src/ov_SC06_010/ov_SC06_010_jr_80135888.c | 24 +- src/ov_SC06_011/ov_SC06_011_jr_80135888.c | 24 +- src/ov_SC06_013/ov_SC06_013_jr_80135888.c | 24 +- src/ov_SC06_014/ov_SC06_014_jr_80135888.c | 24 +- src/ov_SC06_015/ov_SC06_015_jr_80135888.c | 24 +- src/ov_SC06_016/ov_SC06_016_jr_80135888.c | 24 +- src/ov_SC06_018/ov_SC06_018_jr_80135888.c | 24 +- src/ov_SC06_020/ov_SC06_020_jr_80135888.c | 24 +- src/ov_SC06_022/ov_SC06_022_jr_80135888.c | 24 +- src/ov_SC06_024/ov_SC06_024_jr_80135888.c | 24 +- src/ov_SC06_025/ov_SC06_025_jr_80135888.c | 24 +- src/ov_SC06_027/ov_SC06_027_jr_80135888.c | 24 +- src/ov_SC06_029/ov_SC06_029_jr_80135888.c | 24 +- src/ov_SC06_030/ov_SC06_030_jr_80135888.c | 24 +- src/ov_SC06_032/ov_SC06_032_jr_80135888.c | 24 +- src/ov_SC06_033/ov_SC06_033_jr_80135888.c | 24 +- src/ov_SC07_000/ov_SC07_000_jr_80135888.c | 24 +- src/ov_SC07_001/ov_SC07_001_jr_80135888.c | 24 +- src/ov_SC07_002/ov_SC07_002_jr_80135888.c | 24 +- src/ov_SC07_006/ov_SC07_006_jr_80135888.c | 24 +- src/ov_SC07_007/ov_SC07_007_jr_80135888.c | 24 +- src/ov_SC07_008/ov_SC07_008_jr_80135888.c | 24 +- src/ov_SC07_009/ov_SC07_009_jr_80135888.c | 24 +- src/ov_SC07_010/ov_SC07_010_jr_80135888.c | 24 +- src/ov_SC07_011/ov_SC07_011_jr_80135888.c | 24 +- src/shared/ov/func_80135888__4a3066ea.h | 24 +- tools/delever.py | 98 ++++- tools/delever_search.py | 16 +- 149 files changed, 2419 insertions(+), 2001 deletions(-) create mode 100644 .run/P36/agents/ov_SC04_011__func_80135888/mechanism.md create mode 100644 .run/P36/agents/ov_SC04_011__func_8013F350/body.c diff --git a/.run/P36/agents/ov_SC04_011__func_80133784/body.c b/.run/P36/agents/ov_SC04_011__func_80133784/body.c index 0fd4b6fa8e..6f72a43670 100644 --- a/.run/P36/agents/ov_SC04_011__func_80133784/body.c +++ b/.run/P36/agents/ov_SC04_011__func_80133784/body.c @@ -7,13 +7,13 @@ s32 func_80133784(s32 arg0, void *arg1, s32 arg2) { extern u16 D_801EDA40; s32 s1; - s32 s2; + u16 s2; s16 s3; s32 s4; s16 a0v; s16 arg0s; s32 dx, dy, dz; - s32 r, ret; + s32 r; a0v = ((s16)arg0); s1 = 0; @@ -60,13 +60,9 @@ s32 func_80133784(s32 arg0, void *arg1, s32 arg2) { loop: { - s32 ret0; - s32 retc; - ret0 = func_80133AB0(arg0s, (s16)D_801909BC->f0, (s16)D_801909BC->f4, (*(s32*)&D_801EDA30)); - retc = ret0; - ret = retc; - if (ret == 0) goto after; - s4 |= ret; + r = func_80133AB0(arg0s, (s16)D_801909BC->f0, (s16)D_801909BC->f4, (*(s32*)&D_801EDA30)); + if (r == 0) goto after; + s4 |= r; if (s2 != 0) goto after; { s16 oldc = s3; diff --git a/.run/P36/agents/ov_SC04_011__func_80135888/body.c b/.run/P36/agents/ov_SC04_011__func_80135888/body.c index ca5b473e36..703b8180a4 100644 --- a/.run/P36/agents/ov_SC04_011__func_80135888/body.c +++ b/.run/P36/agents/ov_SC04_011__func_80135888/body.c @@ -1,6 +1,5 @@ s32 func_80135888(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { s32 pad_[8]; - s32 m; s32 sp; s32 p1; s32 mode; @@ -17,14 +16,12 @@ s32 func_80135888(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { return 0; case 1: base = p0 + 0x34; - m = p1 & 0xFFFFFFF; - sp = m | 0x80000000; + sp = (p1 & 0xFFFFFFF) | 0x80000000; mode = 0; break; case 2: base = p0 + 0x34; - m = p1 & 0xFFFFFFF; - sp = m | 0x80000000; + sp = (p1 & 0xFFFFFFF) | 0x80000000; mode = 1; break; case 3: @@ -41,18 +38,20 @@ s32 func_80135888(s32 arg0, s32 arg1, s32 arg2, s32 arg3) { if (p1 < 0) { if (func_80135EB0(sp, 0) != 0) { - func_80136A94(mode, p0, p3, base); - return 1; + goto hit; } sp = *(s32 *)sp; - while (sp != 0) { + if (sp == 0) { + return 0; + } + do { if (func_80135EB0(sp, 0) != 0) { hit: func_80136A94(mode, p0, p3, base); return 1; } sp = *(s32 *)sp; - } + } while (sp != 0); return 0; } { diff --git a/.run/P36/agents/ov_SC04_011__func_80135888/mechanism.md b/.run/P36/agents/ov_SC04_011__func_80135888/mechanism.md new file mode 100644 index 0000000000..3e7d437e77 --- /dev/null +++ b/.run/P36/agents/ov_SC04_011__func_80135888/mechanism.md @@ -0,0 +1,118 @@ +# func_80135888 (ov_SC04_011_jr_80135888.c) — score 0, all 5 NEEDED levers removed + +Start 29 (COUNT, mine 110 / target 113). Mechanical best over 7 runs and 4,811+ compiles: 16. +**Final: 0 (byte-identical, 113/113).** Three source moves, each proven on bytes and each predicted from a dump +BEFORE it was compiled. + +Levers removed: pins `$2` (m), `$17` (p1), `$19` (p0), `$21` (p3) and the `__asm__ __volatile__("")` barrier @683. +No `register`, no `asm`, no added `volatile`, no `__builtin_*` in the answer. + +## (a) The residual in one sentence + +Three instructions MISSING (the loop's entry test, which the target duplicates and mine reached by a `j` into the +loop's bottom test), a 3-cycle on the callee-saved bank (mine `p0=s1 p1=s2 mode=s3`, target `p1=s1 mode=s2 p0=s3`), +and the `p1 & 0x0FFFFFFF` result in `a0` instead of `v0` (pushing the `lui 0x8000` temp from `v1` to `v0`). + +## (b) The passes and the decisions + +**1. COUNT — `jump.c` cross-jump, run from `toplev.c:3142` (`jump_optimize(…, cross_jump=1, noop_moves=1)`).** +`while (sp)` is rotated to `goto test; loop: … test: if (sp) goto loop;`, so my `sp = *(s32 *)sp;` before the loop was +followed by a simple jump to the bottom test. `jump.c:1969` (`if (cross_jump && simplejump_p (insn))`) calls +`find_cross_jump (insn, JUMP_LABEL (insn), 1, …)` (`jump.c:1978`, body at `jump.c:2371`), which walks backwards from +the jump and from its label in lockstep; the `lw s0,0(s0)` in front of the jump matched the `lw s0,0(s0)` in front of +the label, so `do_cross_jump` (`jump.c:1998`) retargeted the jump *before* that load and deleted my copy — 3 fewer +instructions and no entry test. The `__asm__ __volatile__("")` in the tree was hired to break that backwards match. + +**2. REG (the callee-saved 3-cycle) — `allocno_compare`, `global.c:585-611`.** +All six callee-saved values conflict pairwise, so the whole bank is decided by rank alone: rank *n* takes `$s(n-1)`. +Priority is `floor_log2(refs) * refs / live_length * 10000`, ties by allocno number (= declaration order, +`global.c:609-610`). The `.greg` table for the lever-free body (`tools/alloc_table.py`) read: + +| allocno | var | refs | live | priority | +|---|---|---|---|---| +| r78 | p1 | 5 | 37 | 2702.7 | +| r79 | mode | 7 | 54 | 2592.6 | +| **r80** | **p0** | **8** | **76** | **3157.9** ← outranks both | +| r81 | base | 7 | 76 | 1842.1 | +| r82 | p3 | 5 | 73 | 1369.9 | + +Order `76 77 87 **80 78 79** 81 82` → `p0=s1 p1=s2 mode=s3`. The target's order is plain declaration order, so p0 had +to fall below `mode`. `floor_log2` is the whole lever: **8 refs → 3, 7 refs → 2**, so dropping ONE reference from p0 +divides its priority by 1.7. Note `reg_n_refs` is loop-depth weighted (`flow.c:2067/2315/2501`), and the second +`func_80136A94(mode, p0, p3, base)` sits inside the loop, i.e. it is worth 2 refs; the first copy of that same call +(before the loop) is worth 1. Deleting the duplicated call — writing `goto hit;` instead — takes exactly one ref off +p0, mode, p3 and base. Predicted new order: p1 > mode > p0 > base > p3. Measured on the c2 dump: +`;; 8 regs to allocate: 76 77 87 **78 79 80** 81 82`, priorities 2702.7 / 2264.2 / 1891.9 / 1666.7 / 1142.9 — the +prediction was exact, and the score went 22 → 6 with all three pairs closed. + +**That rewrite is byte-neutral by itself.** `if (…) goto hit;` compiles to `bnez v0,`; `fill_simple_delay_slots` +steals the branch target's first insn into the delay slot and retargets the branch past it +(`reorg.c:3095-3135`, `reorg_redirect_jump (insn, new_label)` at `:3135`) — producing `bnez v0,0x100` / +`move a0,s2`, which is exactly what cross-jump had left of the duplicated call. So the move changes only `reg_n_refs`. + +**3. REG (`m` in a0) — `local-alloc.c:470-477` + the `combine_regs` bail at `local-alloc.c:1774`.** +`m` is assigned in two switch arms, so `reg_n_deaths[m] == 2` and it fails the gate at `local-alloc.c:472` +(`reg_basic_block[i] >= 0 && reg_n_deaths[i] == 1`): `reg_qty[m] = -1`, never a local quantity. `block_alloc` then +cannot tie the `and`'s destination to the dying `0x0FFFFFFF` pseudo, because `combine_regs` bails at +`local-alloc.c:1773-1774` — *"Can't combine if SREG is not a register we can allocate"*, +`(sreg >= FIRST_PSEUDO_REGISTER && reg_qty[sreg] == -1)`. `m` therefore fell through to `global.c` and took its copy +preference (`;; 76 preferences: 4 7` = `a0`, `a3`), leaving `v0` free for the `lui 0x8000` temp. Inlining the +expression gives each arm its own single-death, single-block temp, which `block_alloc` ties to the dying mask pseudo +in `v0`, so the `and` writes `v0` in place and `lui` first-fits `v1`. Proven: after the change the `.greg` order line +has only 7 allocnos and `m` is gone from it entirely (`76 88 77 78 79 80 81`, r76 is now `sp`). Score 6 → 0. + +## (c) The moves (one line each) + +1. `while (sp != 0) {…}` → `if (sp == 0) { return 0; } do {…} while (sp != 0);` — 29 → **22**, COUNT closed (113/113). +2. The duplicated `func_80136A94(mode, p0, p3, base); return 1;` before the loop → `goto hit;` — 22 → **6**. +3. `m = p1 & 0xFFFFFFF; sp = m | 0x80000000;` → `sp = (p1 & 0xFFFFFFF) | 0x80000000;` — 6 → **0**. + +`PACK/body.c` is move 3 as written above. `PACK/scratch/c4.c` also scores 0 and keeps the name — it scopes the temp +instead (`{ s32 m = p1 & 0xFFFFFFF; sp = m | 0x80000000; }`); same mechanism, one brace-block per arm. Pick whichever +reads better in the tree; the inlined form is shipped because it is one line shorter and needs no synthetic block. + +## (d) GENERATOR PROPOSALS + +**G1 — `goto_merges` (the important one; a REF-COUNT lever that costs zero bytes).** +When the residual is register-only and the callee-saved colours are a permutation, find any statement block in the +body that is textually identical to another block which carries (or can be given) a label, and replace the duplicate +with `goto