Skip to content

Add five passes and resumable runs (--resume) - #4

Merged
MrSapps merged 2 commits into
claude/blissful-johnson-1w5a5vfrom
claude/manual-passes
Oct 4, 2026
Merged

MrSapps merged 2 commits into
claude/blissful-johnson-1w5a5vfrom
claude/manual-passes

Conversation

@MrSapps

@MrSapps MrSapps commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

New passes (src/passes_manual.cpp)

These are rewrites that kept coming up when matching gta2_re functions by hand:

  • cache_member: reads a member path used in the function into a local first. It tries three forms: T c = p->f;, T& c = p->f;, and for a struct, T* c = &p->f;. It does this for all uses or just the first. The type comes from the member declarations in the source and the headers it includes (findFieldTypes, collected next to the getters). Names declared with two different types are skipped.
  • ref_local: switches between T x = e;, const T& x = e; and T& x = e;. A named local gets its own stack slot, while a temporary bound to a reference may share one.
  • incdec: switches between x++, ++x, x += 1 and x = x + 1, in expression statements and for-steps.
  • cond_temp: computes an if condition into an s32/u8/bool local first.
  • pow2_shift: switches between x * 4 and x << 2, and turns x / 4 into x >> 2, including the compound forms. The two can differ for negative values, so check the diff before using a result.

localTypes moved out of the anonymous namespace so the new file can use it. docs/passes.md is regenerated and has an example for each new pass.

Resumable runs

  • Numbered candidates: every candidate gets an index.
    • In random mode, each candidate has its own generator, seeded from the seed and its index. With -j 1 a seed always gives the same candidates in the same order.
    • With more jobs, a candidate can also depend on which improvements had landed when it was generated (--keep-prob). A resumed run still never repeats an index or a candidate it already tried.
  • Checkpoint files: checkpoint.txt, checkpoint_best.txt and checkpoint_seen.txt are written to the output dir every couple of seconds and on exit, including Ctrl-C. They hold the position, the seed, the counts, the best candidate and the hashes of the candidates already tried.
  • --resume: carries on from the first candidate that wasn't scored.
    • It refuses if the key differs. The key covers the function's source, the mode, -p, --weight, --op-alias, --depth, --max-mutations and --keep-prob.
    • -n counts only the new run's compiles; --max-candidates counts the whole search.
  • Exhaustive mode: the order doesn't depend on the scores, so a resumed run replays the earlier candidates without compiling them. It then continues with exactly the candidates that weren't scored.
  • Hashes: candidate hashes now use FNV-1a, so they are the same on every build and platform.

Tests

  • Unit and integration suites pass under ctest.
  • I didn't run the vc6 suite (tests/integration/vc6.sh). The new passes were used against real VC6 through gta2_re's Scripts/permute.sh, which found matches for Trailer::sub_407BD0 and gtx_0x106C::GetSpriteTrueIndex_5AA460. A resumed run took Map_0x370::sub_4E6660 from 48 diff lines to 4.
  • New integration checks: a random run of 40 candidates and an exhaustive run of 30 are each compared with the same run split in two and resumed. Their checkpoint and seen hashes must be identical.
  • Manual checks:
    • An exhaustive depth-2 run cut off after 25 candidates and resumed ended identical to an uninterrupted run: 4102 compiles, the same best score and the same outputs.
    • Ctrl-C mid-run leaves a checkpoint.
  • Changed test: the local_type random integration run now accepts an equivalent match. With the new seeding, the fixed-seed run lands on unsigned long x instead of unsigned int x. They are the same type at i686 -O0, the same allowance the other passes with equivalent forms already have.

🤖 Generated with Claude Code

claude added 2 commits October 4, 2026 09:42
Rewrites that kept coming up when matching gta2_re functions by hand.
cache_member reads member types from the declarations in the included
headers (findFieldTypes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each candidate gets an index, and in random mode its own generator seeded
from (seed, index), so -j 1 is deterministic and a run can continue from
any index. A checkpoint (position, seed, counts, best candidate, hashes of
the candidates tried) is written to the output dir every couple of seconds
and on exit; --resume carries on from it if the function and search
options are unchanged. Exhaustive mode replays the earlier candidates
without compiling them, so a resumed run continues with exactly the ones
that weren't scored. Candidate hashes use FNV-1a so they are stable
across builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MrSapps
MrSapps merged commit 3893237 into claude/blissful-johnson-1w5a5v Oct 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants