mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-29 15:18:24 -04:00
phase-36: generator R39 duplicate_join_statement (the integer-tie split of e12/e14; known-true 0 on two of three)
This commit is contained in:
+1
-1
@@ -1840,7 +1840,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), **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), **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).
|
||||
- **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
|
||||
|
||||
+40
-1
@@ -3479,6 +3479,42 @@ def shift_to_division(text, tu, fn, d_):
|
||||
return out
|
||||
|
||||
|
||||
def duplicate_join_statement(text, tu, fn, d_, max_sites=12):
|
||||
"""[(description, candidate text)] — R39: the single simple statement right after an if/else's closing brace copied to
|
||||
the end of BOTH arms (and deleted after the join), one site at a time.
|
||||
|
||||
T7 agents e12 (func_8017E35C) and e14 (func_8017BEBC, func_8017CAD4), P36 S104: `global.c:594-603` truncates allocno
|
||||
priorities to int, so two loop-live pseudos tie (245/245) and the lower allocno takes the wrong register. One extra insn
|
||||
inside the loop lengthens every loop-live pseudo by one (flow.c:1660-1684) and splits the tie (244 vs 245); post-reload
|
||||
cross-jump merges the two copies back into one (`toplev.c:3142`, `jump.c:2371`), so the bytes keep a single store.
|
||||
`tools/alloc_table.py` flags such ties as TIE."""
|
||||
lines = text.split("\n")
|
||||
masked = sc.mask_text(text).split("\n")
|
||||
lo, hi = d_["line"], d_["end"] - 1
|
||||
out = []
|
||||
for k in range(lo + 1, hi):
|
||||
if not re.match(r"^\s*\}\s*$", masked[k - 1]) or not simple_stmt(masked[k]) or is_decl_line(masked[k].strip()):
|
||||
continue
|
||||
# find the matching `if (…) {` … `} else {` … `}` that closes at k-1
|
||||
depth, j, else_at = 0, k - 1, None
|
||||
while j >= lo:
|
||||
depth += masked[j].count("}") - masked[j].count("{")
|
||||
if re.match(r"^\s*\}\s*else\s*\{\s*$", masked[j]) and depth == 1:
|
||||
else_at = j
|
||||
if depth == 0:
|
||||
break
|
||||
j -= 1
|
||||
if else_at is None or j < lo or not re.match(r"^\s*if\s*\(", masked[j]):
|
||||
continue
|
||||
ind = lines[else_at][:len(lines[else_at]) - len(lines[else_at].lstrip())] + " "
|
||||
stmt = lines[k].strip()
|
||||
cand = lines[:else_at] + [ind + stmt] + [lines[else_at]] + lines[else_at + 1:k - 1] + [ind + stmt, lines[k - 1]] + lines[k + 1:]
|
||||
out.append((f"dup-join {stmt[:24]} @{k + 1}", "\n".join(cand)))
|
||||
if len(out) >= max_sites:
|
||||
break
|
||||
return out
|
||||
|
||||
|
||||
def return_constants(text, tu, fn, d_):
|
||||
"""[(description, candidate text)] — R37: a result local `r = 0; if (A) r = (B); return r;` (or with `{ }`) written as
|
||||
`if (A && B) return 1; return 0;` — and the nested form `if (A) { if (B) return 1; } return 0;`.
|
||||
@@ -3748,7 +3784,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")
|
||||
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")
|
||||
RUNG_R_FAMILIES = ("R2", "R3", "R4", "R5", "R6", "R7") # the free sweep's set (R8/R9 are the search engine's until measured)
|
||||
|
||||
|
||||
@@ -3907,6 +3943,9 @@ def recipe_candidates(text, tu, fn, names, limit=24, rng=None, cap=40, blocks=Tr
|
||||
if "R36" in fam:
|
||||
for desc, cand in merge_set_chains(text, tu, fn, d_):
|
||||
out.append(("R36", desc, cand))
|
||||
if "R39" in fam:
|
||||
for desc, cand in duplicate_join_statement(text, tu, fn, d_):
|
||||
out.append(("R39", desc, cand))
|
||||
if "R38" in fam:
|
||||
for desc, cand in shift_to_division(text, tu, fn, d_):
|
||||
out.append(("R38", desc, cand))
|
||||
|
||||
Reference in New Issue
Block a user