phase-36: S105 harvest f2 — generator R44 counter_derived_pointer (known-true 0 on e21's start text, 18 on f2's loop 2), R22 extended to same-base offsets, the && read-as-&p refusal in R22/R44 fixed; selftest OK

This commit is contained in:
Drew T
2026-09-11 11:56:31 -06:00
parent e4fdd3c8f5
commit ae522dbc49
3 changed files with 237 additions and 9 deletions
+1 -1
View File
@@ -1841,7 +1841,7 @@ CLAIM, not a fact — two were refuted on bytes on 2026-09-10.**
R28 …` feeds R28 the real TU like R27. **Then (S104, from d22/d24/d25):** **R23 accepts a `case K:` / `default:` label as a
statement boundary** (it had refused d22's `t` after `case 2:`; known-true `split t into 2` → 0); **R35 `drop_param_copies`**
(`T x = argN;` never reassigned → `argN` used; d24's start 36 → 23 — its close was joint); **R36 `merge_set_chains`** (`x = A;
[≤2 unrelated lines] x += B;` → one assignment; d25's frame-only residual; known-true 0). **R31 widened** (d39: an all-shifts `(s16)` candidate — its two sites closed only together; known-true 0), **R35 widened** (d38: a CAST copy `T *p = (T *)a1;` becomes `((T *)a1)` at each use; known-true 0), `named_definitions` indexes `func_X_body(` asm-label definitions (two bank lists failed to resolve them); **R38 `shift_to_division`** (e7: `if (v < 0) v += 2^k-1; v = v >> k;` — gcc's own expansion — written `v = v / 2^k;` or merged into the preceding `v = (E) / 2^k;`; on e7's start text alone 6 → 6/7: e7's close was joint with a width move, so R38 is a composition move; 7 residue bodies carry the shape), **R39 `duplicate_join_statement`** (e12/e14: the simple statement after an if/else join copied into both arms to split an integer-truncated `allocno_compare` tie — cross-jump re-merges the copies; known-true 0 on e14's func_8017BEBC and func_8017CAD4; needs the `} else {` line shape — e12's func_8017E35C produced no candidate; widened S104: the first 1–3 simple statements after the join, blank lines skipped — e24's func_80180E24 store pair closes at ×2), **R40 `return_preincrement`** (e2/e16: `return i + 1;` → `return ++i;`, zero bytes, more refs; known-true 0 on both), **R41 `swap_if_else_arms`** (e16: `if (C) {A} else {B}` → `if (!C) {B} else {A}`, one site at a time — the arm order decides reorg's delay-slot steal; known-true 0), **R42 `move_statement_far`** (e19: one simple statement moved 2–6 simple statements down within its block — R9 only swaps neighbours; on e19's func_8018230C start text alone best 8: its close also inlined a temp and dropped an inner block, so R42 is a composition move), **R43 `sign_test_to_mask`** (e24/e26: `if (E < 0)` whose arms set/clear bit 31 → `if ((u32)(E) & 0x80000000)`, plus the variant with never-used pad arrays dropped; alone 9 / 4 on the two start texts — both closes also deleted temps: a composition move), **R37 `return_constants`** (d27: a result local `r = 0; if (A) r = (B); return r;` → `if (A && B) return 1; return 0;` or the nested form — jump1's store-flag on the hard `$v0`; known-true 0 both spellings).
[≤2 unrelated lines] x += B;` → one assignment; d25's frame-only residual; known-true 0). **R31 widened** (d39: an all-shifts `(s16)` candidate — its two sites closed only together; known-true 0), **R35 widened** (d38: a CAST copy `T *p = (T *)a1;` becomes `((T *)a1)` at each use; known-true 0), `named_definitions` indexes `func_X_body(` asm-label definitions (two bank lists failed to resolve them); **R38 `shift_to_division`** (e7: `if (v < 0) v += 2^k-1; v = v >> k;` — gcc's own expansion — written `v = v / 2^k;` or merged into the preceding `v = (E) / 2^k;`; on e7's start text alone 6 → 6/7: e7's close was joint with a width move, so R38 is a composition move; 7 residue bodies carry the shape), **R39 `duplicate_join_statement`** (e12/e14: the simple statement after an if/else join copied into both arms to split an integer-truncated `allocno_compare` tie — cross-jump re-merges the copies; known-true 0 on e14's func_8017BEBC and func_8017CAD4; needs the `} else {` line shape — e12's func_8017E35C produced no candidate; widened S104: the first 1–3 simple statements after the join, blank lines skipped — e24's func_80180E24 store pair closes at ×2), **R40 `return_preincrement`** (e2/e16: `return i + 1;` → `return ++i;`, zero bytes, more refs; known-true 0 on both), **R41 `swap_if_else_arms`** (e16: `if (C) {A} else {B}` → `if (!C) {B} else {A}`, one site at a time — the arm order decides reorg's delay-slot steal; known-true 0), **R42 `move_statement_far`** (e19: one simple statement moved 2–6 simple statements down within its block — R9 only swaps neighbours; on e19's func_8018230C start text alone best 8: its close also inlined a temp and dropped an inner block, so R42 is a composition move), **R43 `sign_test_to_mask`** (e24/e26: `if (E < 0)` whose arms set/clear bit 31 → `if ((u32)(E) & 0x80000000)`, plus the variant with never-used pad arrays dropped; alone 9 / 4 on the two start texts — both closes also deleted temps: a composition move), **R37 `return_constants`** (d27: a result local `r = 0; if (A) r = (B); return r;` → `if (A && B) return 1; return 0;` or the nested form — jump1's store-flag on the hard `$v0`; known-true 0 both spellings). **(S105) R44 `counter_derived_pointer`** (e21/f2: a pointer initialised before a counted loop and stepped `p += K` inside it — its own biv, never eliminated while a bare `p[0]` is read (`loop.c:4196`, `:6022`) — re-derived as `p = (T *)(BASE) + i * K;` at the loop top for each up-counter `i` of that block (`(i - C)` when it starts at C; a second `&SYM[c + i * K]` spelling for an uncast symbol base); refuses a down-counter, a second assignment, `&p`; known-true: alone 0 on e21's func_80037EA0 start text (from 33) and f2's measured 18 on func_80038838's loop 2; composed with R22 it reaches f2's 0). **R22 extended + a blind spot fixed (S105):** two pointers derived from ONE base expression at two offsets (`a1 = (u8 *)arg0 + 0x1B` beside `a3 = … + 0x1A`) merge like `q = p + K` (f2's loop 1, alone 3); and R22/R44's `&p` refusal had matched the `&&` operator (`… != 0 && p[0]`) since S103 — every body testing its pointer with `&&` was silently never offered R22 (fixed to `(?<!&)&(?!&)`; the S105 regen re-runs R22).
- **Generator R27 `named_ports` (`tools/delever.py`, S104; `delever_regen --families R27`)** — the SAME function already
lever-free in another binary, ported. Donors: every definition of the name in `src/` (`named_definitions()`, one `git
grep`, cached) with no `register`/`__asm__`/`!FAKE`, nearest line count first, ≤ 6 distinct texts. Symbol renaming by
+231 -3
View File
@@ -2733,7 +2733,7 @@ def merge_walked_pointers(text, tu, fn, d_):
out = []
for q, (qi, qt) in ptrs.items():
qn = re.escape(q)
if re.search(r"&\s*%s\b" % qn, "\n".join(masked[lo:hi])):
if re.search(r"(?<!&)&(?!&)\s*%s\b" % qn, "\n".join(masked[lo:hi])):
continue
init, steps = None, []
ok = True
@@ -2746,7 +2746,30 @@ def merge_walked_pointers(text, tu, fn, d_):
m = (re.match(r"^%s\s*=\s*([A-Za-z_]\w*)\s*([+-])\s*%s\s*;$" % (qn, _INT), s)
or re.match(r"^%s\s*=\s*&\s*([A-Za-z_]\w*)\s*\[\s*(-?)\s*%s\s*\]\s*;$" % (qn, _INT), s)
or re.match(r"^%s\s*=\s*([A-Za-z_]\w*)\s*;$()()" % qn, s))
if init is not None or not m or m.group(1) not in ptrs or m.group(1) == q:
if init is None and (not m or m.group(1) not in ptrs or m.group(1) == q):
# S105 f2 (func_80038838): `q = (T *)arg0 + 0x1B;` beside `p = (T *)arg0 + 0x1A;` — the same BASE
# expression at two offsets is `q = p + (c1 - c2)` in all but spelling; the lockstep test still applies
m2 = re.match(r"^%s\s*=\s*(.+?)\s*(?:([+-])\s*%s)?\s*;$" % (qn, _INT), s)
if m2:
E, sign, k = " ".join(m2.group(1).split()), m2.group(2), m2.group(3)
c1 = (int(k, 0) if k else 0) * (-1 if sign == "-" else 1)
for p2, (p2i, p2t) in ptrs.items():
if p2 == q or p2t != qt:
continue
for j in assigns(p2):
m3 = re.match(r"^%s\s*=\s*(.+?)\s*(?:([+-])\s*%s)?\s*;$" % (re.escape(p2), _INT), masked[j].strip())
if m3 and " ".join(m3.group(1).split()) == E and j < i and _step_of(masked[j], p2) is None:
c2 = (int(m3.group(3), 0) if m3.group(3) else 0) * (-1 if m3.group(2) == "-" else 1)
m, p_base, K_ = True, p2, c1 - c2
break
if m is True:
break
if m is not True:
ok = False
break
init = (i, p_base, K_)
continue
if init is not None or not m:
ok = False
break
p, sign, k = m.group(1), m.group(2), m.group(3)
@@ -3641,6 +3664,147 @@ def sign_test_to_mask(text, tu, fn, d_):
return out
def counter_derived_pointer(text, tu, fn, d_):
"""[(description, candidate text)] — R44: a WALKED pointer re-derived from the loop's COUNTER.
T7 agents e21 (func_80037EA0/func_80037F3C, S104) and f2 (func_80038838 loop 2, func_800385C0, S105): a pointer local
`p` initialised before a counted loop and stepped `p += K` inside it is its own basic induction variable; a bare `p[0]`
(or any direct `(mem (reg biv))`) is never a giv (`loop.c:4196-4197`), so `maybe_eliminate_biv` fails ("Cannot
eliminate biv N: biv used in insn", `-dL`, `loop.c:6022-6024`) and the body walks TWO registers where the original
walked one — a COUNT residual the `$16`/`$3` pins hid. Written `p = (T *)(BASE) + i * K;` at the top of the loop body,
`p` is a DEST_REG giv of the counter (`record_giv`, `loop.c:4341`) and reduces into ONE register with every `p[c]` a
displacement off it; the counter stays (it is the loop test / a call argument).
The rewrite: `p`'s single initialiser `p = BASE;` (or the declaration's initialiser) and its single step `p += K` /
`p = p + K` are deleted and `p = (T *)(BASE) + i * K;` is inserted as the first statement of the innermost loop block
that holds the step, for each counter `i` of that block (a local stepped by exactly `++`/`+= 1` in the block or in the
`for` header) whose last assignment before the loop is an integer literal C (`(i - C)` when C != 0). A second spelling
`&SYM[c + i * K]` is offered when BASE is `SYM` / `&SYM[c]`. Refused: a pointer with another assignment or `&p`, a
step of 0, a counter stepped elsewhere in the block, a down-counter, a loop with no brace block, a `#` line in the body.
The byte oracle judges the candidate like every other; the do-while/while shape is kept (a `for` spelling moves the
counter's register on the S105 bodies)."""
lines = text.split("\n")
masked = [sc.mask_text(l) for l in lines]
lo, hi = d_["line"], d_["end"] - 1
if any(l.lstrip().startswith("#") for l in lines[lo:hi]):
return []
DECLP = re.compile(r"^(\s*)((?:const\s+|unsigned\s+|signed\s+|struct\s+)*[A-Za-z_]\w*)\s*\*\s*([A-Za-z_]\w*)\s*(?:=\s*(.+?))?\s*;\s*$")
ptrs = {}
for i in range(lo, hi):
m = DECLP.match(masked[i])
if m:
ptrs[m.group(3)] = (i, " ".join(m.group(2).split()), m.group(4))
body = "\n".join(masked[lo:hi])
def assigns(name):
n = re.escape(name)
a = re.compile(r"(?<![\w.>])%s\s*(?:=(?!=)|\+=|-=|\+\+|--)|(?:\+\+|--)\s*%s\b" % (n, n))
return [i for i in range(lo, hi) if a.search(masked[i])]
def block_of(si):
"""(open-brace line, close-brace line) of the innermost `{ … }` holding line si, or None."""
depth = 0
ob = None
for i in range(si - 1, lo - 1, -1):
depth += masked[i].count("}") - masked[i].count("{")
if depth < 0:
ob = i
break
if ob is None:
return None
depth = 0
for i in range(ob, hi):
depth += masked[i].count("{") - masked[i].count("}")
if depth <= 0:
return ob, i
return None
out = []
for p, (pi, pt, pinit) in ptrs.items():
pn = re.escape(p)
if re.search(r"(?<!&)&(?!&)\s*%s\b" % pn, body):
continue
init, steps, ok = None, [], True
if pinit is not None:
init = (pi, lines[pi][lines[pi].index("=") + 1:].strip().rstrip(";").strip())
for i in assigns(p):
if i == pi and pinit is not None:
continue
st = _step_of(masked[i], p)
if st is not None:
steps.append((i, st))
continue
m = re.match(r"^%s\s*=\s*(.+?)\s*;$" % pn, masked[i].strip())
if init is not None or not m:
ok = False
break
raw = lines[i].strip()
init = (i, raw[raw.index("=") + 1:].strip().rstrip(";").strip())
if not ok or init is None or len(steps) != 1 or steps[0][1] == 0:
continue
ii, base = init
si, K = steps[0]
if re.search(r"(?<![\w.>])%s\b" % pn, sc.mask_text(base)):
continue # p = p-derived: not a base
blk = block_of(si)
if blk is None or ii >= blk[0]:
continue
ob, cb = blk
if not re.search(r"\b(for|while|do)\b", masked[ob]):
continue
# the counters of that block: stepped by +1 exactly once inside it (or in the `for` header), never assigned inside
inner = range(ob + 1, cb)
cands = {}
for i in list(inner) + [ob]:
for m in re.finditer(r"(?<![\w.>])([A-Za-z_]\w*)\s*(?:\+\+|\+=\s*1\b)|\+\+\s*([A-Za-z_]\w*)\b", masked[i]):
n = m.group(1) or m.group(2)
if n == p or n in ptrs:
continue
cands.setdefault(n, []).append(i)
for cn, where in cands.items():
if len(where) != 1:
continue
cnn = re.escape(cn)
if any(re.search(r"(?<![\w.>])%s\s*(?:=(?!=)|-=|--)|--\s*%s\b" % (cnn, cnn), masked[i]) for i in inner):
continue
# the counter's start value: the last `cn = C;` before the loop (or in the for header)
C = None
for i in range(ob, lo - 1, -1):
m = re.search(r"(?<![\w.>])%s\s*=\s*(-?%s)\s*[;,)]" % (cnn, _INT), masked[i])
if m:
C = int(m.group(1), 0)
break
if i != ob and re.search(r"(?<![\w.>])%s\s*(?:=(?!=)|\+=|-=|\+\+|--)" % cnn, masked[i]):
break
if C is None:
continue
idx = cn if C == 0 else f"({cn} - {C})"
hexlike = "0x" in masked[si]
ks = (hex(abs(K)) if hexlike else str(abs(K)))
if K < 0:
idx = f"-{cn}" if C == 0 else f"({C} - {cn})"
b, cast_stripped = base, False
if b.startswith(f"({pt} *)"):
b, cast_stripped = b[len(f"({pt} *)"):].strip(), True
spellings = [f"{p} = ({pt} *)({b}) + {idx} * {ks};"]
m = re.match(r"^&?\s*([A-Za-z_]\w*)\s*(?:\[\s*(%s)\s*\])?$" % _INT, b)
if m and not cast_stripped:
c0 = int(m.group(2), 0) if m.group(2) else 0
spellings.append(f"{p} = &{m.group(1)}[{(hex(c0) + ' + ') if c0 else ''}{idx} * {ks}];")
indent = re.match(r"^\s*", lines[si]).group(0)
for k, sp in enumerate(spellings):
cand = list(lines)
if pinit is not None and ii == pi:
cand[pi] = lines[pi][:lines[pi].index("=")].rstrip() + ";"
else:
cand[ii] = None
cand[si] = None
cand.insert(ob + 1, indent + sp)
out.append((f"counter-ptr {p} by {cn}{' array' if k else ''} @{ob + 1}",
"\n".join(l for l in cand if l is not None)))
return out
def _drop_dead_pads(lines, lo, hi):
"""lines with every never-used (or only `(void)&x;`-used) array local deleted; None if there is none."""
masked = [sc.mask_text(l) for l in lines]
@@ -3928,7 +4092,7 @@ def named_ports(tu, fn, max_donors=6):
return out
ALL_FAMILIES = ("R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R31", "R32", "R33", "R34", "R35", "R36", "R37", "R38", "R39", "R40", "R41", "R42", "R43")
ALL_FAMILIES = ("R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R31", "R32", "R33", "R34", "R35", "R36", "R37", "R38", "R39", "R40", "R41", "R42", "R43", "R44")
RUNG_R_FAMILIES = ("R2", "R3", "R4", "R5", "R6", "R7") # the free sweep's set (R8/R9 are the search engine's until measured)
@@ -4093,6 +4257,9 @@ def recipe_candidates(text, tu, fn, names, limit=24, rng=None, cap=40, blocks=Tr
if "R43" in fam:
for desc, cand in sign_test_to_mask(text, tu, fn, d_):
out.append(("R43", desc, cand))
if "R44" in fam:
for desc, cand in counter_derived_pointer(text, tu, fn, d_):
out.append(("R44", desc, cand))
if "R42" in fam:
for desc, cand in move_statement_far(text, tu, fn, d_):
out.append(("R42", desc, cand))
@@ -5289,6 +5456,67 @@ def selftest():
fail(f"R25 must re-issue the call at the real arity: {t25!r}")
_defs.pop("func_8FFFFFF0", None)
# R44, the counter-derived pointer (T7 agents e21 S104 + f2 S105; known-true: alone it reproduces e21's close of
# func_80037EA0 at 0 from 33, and on f2's func_80038838 start text scores the agent's "loop 2 alone" 18; composed with
# the extended R22 it reaches f2's 0). The fixture: a do-while with a counter and a walked pointer, an `&&` test on the
# pointer (the S103–S105 R22 blind spot: `&& p` read as `&p` and refused every such body), a down-counter control.
CFIX = ("void func_80100000(void *arg0) {\n"
" u8 *p;\n"
" u8 *q;\n"
" s32 i;\n"
" s32 n;\n"
" i = 0;\n"
" p = D_800C6E2E;\n"
" do {\n"
" if (p[-4] != 0 && p[0] != 0) {\n"
" p[0] = 0;\n"
" }\n"
" i++;\n"
" p += 0x60;\n"
" } while (i < 0x10);\n"
" n = 3;\n"
" q = (u8 *)arg0;\n"
" do {\n"
" q[0x18] = 0;\n"
" q += 8;\n"
" n--;\n"
" } while (n > 0);\n"
"}")
c44 = dict(counter_derived_pointer(CFIX, "src/fx/c.c", "func_80100000",
next(r for r in sc.scan_text(CFIX, "src/fx/c.c", shared_defs=None) if r["form"] == "def")))
if sorted(c44) != ["counter-ptr p by i @8", "counter-ptr p by i array @8"]:
fail(f"R44 must re-derive the up-counted walk (both spellings) and refuse the down-counted one, got {sorted(c44)}")
elif " p = (u8 *)(D_800C6E2E) + i * 0x60;" not in c44["counter-ptr p by i @8"] or \
" p = &D_800C6E2E[i * 0x60];" not in c44["counter-ptr p by i array @8"] or \
"p += 0x60" in c44["counter-ptr p by i @8"] or " p = D_800C6E2E;" in c44["counter-ptr p by i @8"]:
fail(f"R44 must insert the derivation at the loop top and delete the walk and the initialiser: {c44!r}")
# the counter starting at 2: the derivation subtracts it
CF2 = CFIX.replace(" i = 0;\n", " i = 2;\n")
c44b = dict(counter_derived_pointer(CF2, "src/fx/c.c", "func_80100000",
next(r for r in sc.scan_text(CF2, "src/fx/c.c", shared_defs=None) if r["form"] == "def")))
if "p = (u8 *)(D_800C6E2E) + (i - 2) * 0x60;" not in c44b.get("counter-ptr p by i @8", ""):
fail(f"R44 must offset a counter that does not start at 0: {c44b!r}")
# R22 extended (S105 f2): two pointers derived from ONE base expression at two offsets merge like `q = p + K`
MFIX = ("void func_80100000(void *arg0) {\n"
" u8 *a3;\n"
" u8 *a1;\n"
" s32 i;\n"
" a3 = (u8 *)arg0 + 0x1A;\n"
" i = 0;\n"
" a1 = (u8 *)arg0 + 0x1B;\n"
" do {\n"
" a3[0] = i;\n"
" a1[3] = 0x40 && a3[1];\n"
" i++;\n"
" a1 += 0x1A;\n"
" a3 += 0x1A;\n"
" } while (i < 0x10);\n"
"}")
m22 = dict(merge_walked_pointers(MFIX, "src/fx/m.c", "func_80100000",
next(r for r in sc.scan_text(MFIX, "src/fx/m.c", shared_defs=None) if r["form"] == "def")))
if sorted(m22) != ["merge-ptr a1 into a3+1"] or "a3[4] = 0x40 && a3[1];" not in m22["merge-ptr a1 into a3+1"]:
fail(f"R22 must merge two walked pointers derived from one base at two offsets (K = 1): {m22!r}")
# R26, the address alias (T7 agent c45, S103; known-true: on func_80183E3C's start text R26's "second" candidate
# scores 0 from 38 — the agent's close, reproduced by the generator alone)
AAF = ("void func_80100000(void) {\n"
+5 -5
View File
@@ -88,17 +88,17 @@ FAMILIES = {
# R15 (the sink) is the arm-scoped form of the same tie: a value set in every arm of an if/else chain is a CROSS-BLOCK
# pseudo local-alloc never gives a quantity, so the arm holds two quantities and takes block_alloc's unrolled case 2;
# sinking makes it three, and case 3 falls through into case 2 and undoes its own exchange (T7 agent a1, func_80156044).
"REG-caller": ("R19", "R25", "R26", "R23", "R24", "R21", "R6", "R20", "R16", "R8", "R15", "R17", "R5", "R18", "R10", "R12", "R14", "R13", "R3", "R7", "R9", "R2", "R4", "R22"),
"REG-caller": ("R19", "R25", "R26", "R23", "R24", "R21", "R6", "R20", "R16", "R8", "R15", "R17", "R5", "R18", "R10", "R12", "R14", "R13", "R3", "R7", "R9", "R2", "R4", "R22", "R44"),
# the s-bank order is global.c's allocno_compare (ref weight x live length), declaration order only on an exact tie
"REG-callee": ("R19", "R25", "R26", "R23", "R24", "R21", "R20", "R2", "R4", "R3", "R6", "R16", "R8", "R15", "R18", "R12", "R7", "R9", "R17", "R10", "R14", "R13", "R5", "R22"),
"REG-mixed": ("R19", "R25", "R26", "R23", "R24", "R21", "R6", "R20", "R16", "R2", "R15", "R17", "R18", "R5", "R10", "R4", "R3", "R8", "R12", "R13", "R14", "R7", "R9", "R22"),
"REG-callee": ("R19", "R25", "R26", "R23", "R24", "R21", "R20", "R2", "R4", "R3", "R6", "R16", "R8", "R15", "R18", "R12", "R7", "R9", "R17", "R10", "R14", "R13", "R5", "R22", "R44"),
"REG-mixed": ("R19", "R25", "R26", "R23", "R24", "R21", "R6", "R20", "R16", "R2", "R15", "R17", "R18", "R5", "R10", "R4", "R3", "R8", "R12", "R13", "R14", "R7", "R9", "R22", "R44"),
# a copy dies to cse's canon_reg or the local-alloc tie unless its destination changes MODE (the width); an address
# pseudo lives when a pointer local is used twice; a value named once is computed once; a short PARAMETER is extended in place
"COUNT": ("R19", "R25", "R26", "R22", "R21", "R20", "R12", "R16", "R14", "R15", "R6", "R8", "R3", "R18", "R7", "R17", "R5", "R13", "R9", "R10", "R2", "R4", "R23", "R24"),
"COUNT": ("R19", "R25", "R26", "R22", "R44", "R21", "R20", "R12", "R16", "R14", "R15", "R6", "R8", "R3", "R18", "R7", "R17", "R5", "R13", "R9", "R10", "R2", "R4", "R23", "R24"),
# statement order IS the schedule among equal-priority insns (rank_for_schedule's LUID tie-break); do-while is a barrier
# R17 is the DIRECTED form of the run-split R9 reaches only by luck: agent a2 measured 2,271 compiles for R9 to find it
# in func_80168828 and R16+R17 reproduce the same close in ten.
"ORDER": ("R19", "R25", "R17", "R18", "R20", "R21", "R9", "R7", "R13", "R3", "R16", "R6", "R8", "R5", "R12", "R14", "R10", "R15", "R2", "R4", "R22", "R23", "R24", "R26"),
"ORDER": ("R19", "R25", "R17", "R18", "R20", "R21", "R9", "R7", "R13", "R3", "R16", "R6", "R8", "R5", "R12", "R14", "R10", "R15", "R2", "R4", "R22", "R23", "R24", "R26", "R44"),
"MIXED": dl.ALL_FAMILIES,
"OTHER": dl.ALL_FAMILIES,
}