Repository navigation
v0.7.0
asmlift 0.7.0 lifts one function's assembly to source that recompiles byte-identical. This release renames the
enumeration's vocabulary, which is an npm API break with no aliases. It also re-sources the kleod benchmark by ROM
address, and adds the Fan Explorer, a benchmark page that defines, prices and shows every variation asmlift
enumerates.
Measured against 0.6.0
Both releases use the same pinned m2c (ad5c529a). The numbers come from each release's committed results.json.
| 0.6.0 | 0.7.0 | ||
|---|---|---|---|
| benchmark rows | 1,022 | 1,064 | +42 |
| asmlift byte-exact | 581 | 626 | +45 |
| — synthetic rows | 501 / 770 | 546 / 812 | +45 |
| — real project rows | 80 / 252 | 80 / 252 | ±0 (see kleod below) |
| m2c byte-exact | 407 | 416 | +9 |
| matches lost, over the 986 rows present in both releases | 0 (8 gained) |
Real decompilation projects, byte-exact rows out of 42 each:
| project | 0.6.0 | 0.7.0 |
|---|---|---|
| pokeemerald (GBA) | 22 | 23 |
| kleod (GBA) | 21 | 19 ¹ |
| sa3 (GBA) | 15 | 15 |
| marioparty3 (N64) | 15 | 15 |
| af (N64) | 4 | 4 |
| snowboardkids2 (N64) | 3 | 4 |
¹ Not comparable. kleod's 42 rows are now drawn from testyourmine/kleod and keyed by ROM address (#198). They are a
different set of functions, not the same functions scoring worse. No row in the other five projects moved in that swap.
A second check ran the CLI the way a user does, from each project's root. Both releases decompiled 3,541 undecompiled
functions drawn from the checkouts' own asm/ trees:
- GBA: sa3, kleod, FireEmblem7J.
- N64: marioparty3, af, snowboardkids2.
The result was 0 regressed and 1 newly lifted. 3,423 outputs are byte-identical; the other 118 carry the improvements
below. The packages as published to npm were then installed from the registry and run over the same 3,541 functions, and
every output and stderr was byte-identical to the build the release gates tested.
Breaking changes
The enumeration's words are now candidate, fan, winner, variation, dropped, withheld (#199). docs/vocabulary.md
defines them. axis, lever, variant, and label for a candidate's name are gone, and a candidate's name is now its
list of variations.
| Package | Old | New |
|---|---|---|
@asmlift/core/rank-axes |
the module | @asmlift/core/rank-variations |
@asmlift/core/rank-variations |
STRUCTURING_AXES / StructuringAxis (.probeGate, .variantGate) |
STRUCTURE_VARIATIONS / StructureVariation (.sharedGate, .perLiftGate) |
SHAPE_PRODUCTS / SHAPE_SUBSETS / applyShapes |
STACKED_VARIATIONS / STACKED_SUBSETS / applyStacked |
|
PRE_FAN_PRODUCTS |
PRE_RESPELL_VARIATIONS |
|
LIVEBASE_ / BASEFOLD_ / UNFOLDED_ / ORDERBASE_ADMISSIONS; BaseAdmission |
*_HOISTS; BaseHoist |
|
SIGN_CANDS ([i].label) |
SIGNEDNESS ([i].variation) |
|
@asmlift/core/rank |
Candidate.label: string, DroppedCandidate.label, WithheldCandidate.label |
.variations: readonly string[] |
Candidate.group |
Candidate.preference |
|
RankedResult.best |
RankedResult.winner |
|
composeLevers |
composeRespellVariations |
|
EnumerateOptions.onLeverError(label, error) |
onEnumerationError(variations, error) |
|
EnumerateOptions.onAxisGated(suffix) |
onVariationGated(variation): defsite, not /defsite |
|
@asmlift/core/variation-tokens (new) |
— | VARIATION_TOKENS, VARIATION_KINDS, variationToken, parseVariation, hasVariation, hasVariations, joinVariations, splitVariations |
@asmlift/core/variation-definitions (new) |
— | VARIATION_DEFINITIONS, VARIATION_KIND_DEFINITIONS, READER_WORDS |
@asmlift/cli |
RankOptions.onLeverError |
onEnumerationError |
CandidateReport.label (DecompileReport.candidates[]) |
CandidateReport.variations: readonly string[] |
|
rankedSummaryLine({ best }) |
rankedSummaryLine({ winner }) |
Printed output.
asmlift: [lever] <name> threw …is nowasmlift: [threw] <function> <variations> threw (no candidate from it): ….[ranked] … best <name>:is now[ranked] … winner <name>:.
What is new
- Fan Explorer (#200). A benchmark tab that catalogues every variation by kind: signedness, lift, structure, respell,
and symbol map.- Every variation has a definition. Its example compiles to two different objects, and "offered when" is read from the
gate that decides it. - It prices each variation by candidates per win, and plots cost against win rate.
- The function detail shows the winning spelling, and the variations that were considered and lost.
- Every benchmark row now publishes
fanVariations, which variations its fan carried.
- Every variation has a definition. Its example compiles to two different objects, and "offered when" is read from the
- A closed variation registry (#199, #200). Core mints every variation name through the registry's types, so an
unregistered name is a type error. - Decompilation:
- Early returns recovered from a one-set-arm select diamond (#188).
- A short-circuit's branch sense, read per site from all its facts (#163, #187).
- A cross-jumped store tail, spelled once after the
if(#191) or pushed back into every else-if arm (#169). - Comparison ladders spelled as ladders when the compiler's layout says so (#170).
- Bitfield stores of zero (#168), and variable indices into a pointer global's array member (#167).
- Narrowing casts fused with their scale (#190).
- Pool addresses advanced in place (#196).
- Loop accumulators and nested-loop carried values kept in their variables (#164, #185).
- Unconsumed
volatilereads emitted (#183). - Kleod's
CountCollectedGems, taken from 290 to a byte-exact match over #156–#191.
- Benchmark and tooling:
pnpm bench sweep, a corpus-wide compile-free differential re-lift (#195).- Each row's candidate fan and ranking cost in the artifact (#192).
- An IR oracle for
structure(), so a dropped call fails a test (#193). - One dated cost doc, with a staleness gate (#194).
- Reproducing a row with its own script (#178).
bench fan(#180) andbench gates(#181).- Preflight checks before a run (#175), and denominators on every score (#174).
- The unmatchable-quirks register (#197).
Known limits
- N64 is honest but narrow. The wall is still branch-likely instructions, then hardware float. These are loud
declines, never wrong C. - GameCube / PowerPC still has synthetic rows only, and no real-project coverage. Real rows from three GameCube
decomps are planned next. @asmlift/coreships raw TypeScript. Theasmliftbinary is bundled and runs on stock Node, but importing the library
needs a TypeScript loader such astsx.
Install
npm i -g @asmlift/cli # the binary
npm i @asmlift/core # the library (needs a TS loader)